Merge pull request #23 from mermaid-js/develop

bring up to date
This commit is contained in:
Justin Greywolf 2020-07-28 09:44:50 -07:00 committed by GitHub
commit eda9faf956
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
147 changed files with 335125 additions and 7859 deletions

3
.gitignore vendored
View File

@ -16,4 +16,5 @@ dist/sequenceTest.html
.vscode/
cypress/platform/current.html
cypress/platform/experimental.html
cypress/platform/experimental.html
local/

View File

@ -214,7 +214,7 @@ pie
## Related projects
- [Command Line Interface](https://github.com/mermaid-js/mermaid.cli)
- [Command Line Interface](https://github.com/mermaid-js/mermaid-cli)
- [Live Editor](https://github.com/mermaid-js/mermaid-live-editor)
- [HTTP Server](https://github.com/TomWright/mermaid-server)

View File

@ -1,5 +1,11 @@
/* eslint-env jest */
describe('Rerendering', () => {
it('should be able to render after an error has occured', () => {
const url = 'http://localhost:9000/render-after-error.html';
cy.viewport(1440, 1024);
cy.visit(url);
cy.get('#graphDiv').should('exist');
});
it('should be able to render and rerender a graph via API', () => {
const url = 'http://localhost:9000/rerender.html';

View File

@ -6,6 +6,16 @@ describe('Sequencediagram', () => {
cy.visit(url);
cy.get('body')
.find('svg')
.should('have.length', 2);
.should('have.length', 1);
});
it('should handle html escapings properly', () => {
const url = 'http://localhost:9000/webpackUsage.html?test-html-escaping=true';
cy.visit(url);
cy.get('body')
.find('svg')
.should('have.length', 1);
cy.get('.label > g > foreignobject > div').should('not.contain.text', '<b>');
});
});

View File

@ -71,9 +71,9 @@ describe('Class diagram', () => {
classDiagram
Class01 <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class01 : -int privateMethod()
Class01 : +int publicMethod()
Class01 : #int protectedMethod()
Class01 : -privateMethod()
Class01 : +publicMethod()
Class01 : #protectedMethod()
Class01 : -int privateChimp
Class01 : +int publicGorilla
Class01 : #int protectedMarmoset

View File

@ -0,0 +1,49 @@
/* eslint-env jest */
import { imgSnapshotTest } from '../../helpers/util';
describe('Flowchart v2', () => {
it('1: should render a simple flowchart', () => {
imgSnapshotTest(
`flowchart TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
C -->|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
`,
{}
);
});
it('2: should render a simple flowchart with diagramPadding set to 0', () => {
imgSnapshotTest(
`flowchart TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
%% this is a comment
C -->|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
`,
{ flowchart: { diagramPadding: 0 } }
);
});
it('3: a link with correct arrowhead to a subgraph', () => {
imgSnapshotTest(
`flowchart TD
P1
P1 -->P1.5
subgraph P1.5
P2
P2.5(( A ))
P3
end
P2 --> P4
P3 --> P6
P1.5 --> P5
`,
{ flowchart: { diagramPadding: 0 } }
);
});
});

View File

@ -671,4 +671,27 @@ describe('Flowchart', () => {
{ flowchart: { htmlLabels: false } }
);
});
it('33: should render a simple flowchart with diagramPadding set to 0', () => {
imgSnapshotTest(
`graph TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
%% this is a comment
C -->|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
`,
{ flowchart: { diagramPadding: 0 } }
);
});
it('34: testing the label width in percy', () => {
imgSnapshotTest(
`graph TD
A[Christmas]
`,
{ }
);
});
});

View File

@ -2,6 +2,9 @@
import { imgSnapshotTest } from '../../helpers/util.js';
describe('Gantt diagram', () => {
beforeEach(()=>{
cy.clock((new Date('1010-10-10')).getTime())
})
it('should render a gantt chart', () => {
imgSnapshotTest(
`

View File

@ -126,6 +126,29 @@ context('Sequence diagram', () => {
participant A as Extremely utterly long line of longness which had preivously overflown the actor box as it is much longer than what it should be
A->>Bob: Hola
Bob-->A: Pasten !
`,
{logLevel: 0}
);
});
it('should wrap (inline) long actor descriptions', () => {
imgSnapshotTest(
`
sequenceDiagram
participant A as wrap:Extremely utterly long line of longness which had preivously overflown the actor box as it is much longer than what it should be
A->>Bob: Hola
Bob-->A: Pasten !
`,
{logLevel: 0}
);
});
it('should wrap (directive) long actor descriptions', () => {
imgSnapshotTest(
`
%%{init: {'config': {'wrap': true }}}%%
sequenceDiagram
participant A as Extremely utterly long line of longness which had preivously overflown the actor box as it is much longer than what it should be
A->>Bob: Hola
Bob-->A: Pasten !
`,
{}
);
@ -141,6 +164,17 @@ context('Sequence diagram', () => {
{}
);
});
it('should render long notes wrapped (inline) left of actor', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice->>Bob: Hola
Note left of Alice:wrap: Extremely utterly long line of longness which had preivously overflown the actor box as it is much longer than what it should be
Bob->>Alice: I'm short though
`,
{}
);
});
it('should render long notes right of actor', () => {
imgSnapshotTest(
`
@ -152,6 +186,17 @@ context('Sequence diagram', () => {
{}
);
});
it('should render long notes wrapped (inline) right of actor', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice->>Bob: Hola
Note right of Alice:wrap: Extremely utterly long line of longness which had preivously overflown the actor box as it is much longer than what it should be
Bob->>Alice: I'm short though
`,
{}
);
});
it('should render long notes over actor', () => {
imgSnapshotTest(
`
@ -163,6 +208,17 @@ context('Sequence diagram', () => {
{}
);
});
it('should render long notes wrapped (inline) over actor', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice->>Bob: Hola
Note over Alice:wrap: Extremely utterly long line of longness which had preivously overflown the actor box as it is much longer than what it should be
Bob->>Alice: I'm short though
`,
{}
);
});
it('should render long messages from an actor to the left to one to the right', () => {
imgSnapshotTest(
`
@ -173,6 +229,16 @@ context('Sequence diagram', () => {
{}
);
});
it('should render long messages wrapped (inline) from an actor to the left to one to the right', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice->>Bob:wrap:Extremely utterly long line of longness which had preivously overflown the actor box as it is much longer than what it should be
Bob->>Alice: I'm short though
`,
{}
);
});
it('should render long messages from an actor to the right to one to the left', () => {
imgSnapshotTest(
`
@ -183,6 +249,16 @@ context('Sequence diagram', () => {
{}
);
});
it('should render long messages wrapped (inline) from an actor to the right to one to the left', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice->>Bob: I'm short
Bob->>Alice:wrap: Extremely utterly long line of longness which had preivously overflown the actor box as it is much longer than what it should be
`,
{}
);
});
});
context('background rects', () => {
it('should render a single and nested rects', () => {
@ -216,6 +292,69 @@ context('Sequence diagram', () => {
{}
);
});
it('should render a single and nested opt with long test overflowing', () => {
imgSnapshotTest(
`
sequenceDiagram
participant A
participant B
participant C
participant D
participant E
participant G
A ->>+ B: Task 1
opt this is an opt with a long title that will overflow
B ->>+ C: Task 2
C -->>- B: Return
end
A ->> D: Task 3
opt this is another opt with a long title that will overflow
D ->>+ E: Task 4
opt this is a nested opt with a long title that will overflow
E ->>+ G: Task 5
G -->>- E: Return
end
E ->> E: Task 6
end
D -->> A: Complete
`,
{}
);
});
it('should render a single and nested opt with long test wrapping', () => {
imgSnapshotTest(
`
%%{init: { 'config': { 'wrap': true } } }%%
sequenceDiagram
participant A
participant B
participant C
participant D
participant E
participant G
A ->>+ B: Task 1
opt this is an opt with a long title that will overflow
B ->>+ C: Task 2
C -->>- B: Return
end
A ->> D: Task 3
opt this is another opt with a long title that will overflow
D ->>+ E: Task 4
opt this is a nested opt with a long title that will overflow
E ->>+ G: Task 5
G -->>- E: Return
end
E ->> E: Task 6
end
D -->> A: Complete
`,
{}
);
});
it('should render rect around and inside loops', () => {
imgSnapshotTest(
`
@ -327,5 +466,68 @@ context('Sequence diagram', () => {
{}
);
});
it('should render dark theme from init directive and configure font size 24 font', () => {
imgSnapshotTest(
`
%%{init: {'theme': 'dark', 'config': {'fontSize': 24}}}%%
sequenceDiagram
Alice->>John: Hello John, how are you?
Alice->>John: John, can you hear me?
John-->>Alice: Hi Alice, I can hear you!
John-->>Alice: I feel great!
`,
{}
);
});
it('should render with wrapping enabled', () => {
imgSnapshotTest(
`
%%{init: { 'config': { 'wrap': true }}}%%
sequenceDiagram
participant A as Alice, the talkative one
A->>John: Hello John, how are you today? I'm feeling quite verbose today.
A->>John: John, can you hear me? If you are not available, we can talk later.
John-->>A: Hi Alice, I can hear you! I was finishing up an important meeting.
John-->>A: I feel great! I was not ignoring you. I am sorry you had to wait for a response.
`,
{}
);
});
it('should render with an init directive', () => {
imgSnapshotTest(
`%%{init: { "theme": "dark", 'config': { "fontFamily": "Menlo", "fontSize": 18, "fontWeight": 400, "wrap": true }}}%%
sequenceDiagram
Alice->>Bob: Hello Bob, how are you? If you are not available right now, I can leave you a message. Please get back to me as soon as you can!
Note left of Alice: Bob thinks
Bob->>Alice: Fine!`,
{}
)
});
});
context('directives', () => {
it('should overide config with directive settings', () => {
imgSnapshotTest(
`
%%{init: { "config": { "mirrorActors": true }}}%%
sequenceDiagram
Alice->>Bob: I'm short
note left of Alice: config set to mirrorActors: false<br/>directive set to mirrorActors: true
Bob->>Alice: Short as well
`,
{ logLevel:0, sequence: { mirrorActors: false, noteFontSize: 18, noteFontFamily: 'Arial' } }
);
});
it('should overide config with directive settings', () => {
imgSnapshotTest(
`
%%{init: { "config": { "mirrorActors": false, "wrap": true }}}%%
sequenceDiagram
Alice->>Bob: I'm short
note left of Alice: config: mirrorActors=true<br/>directive: mirrorActors=false
Bob->>Alice: Short as well
`,
{ logLevel:0, sequence: { mirrorActors: true, noteFontSize: 18, noteFontFamily: 'Arial' } }
);
});
});
});

View File

@ -0,0 +1,280 @@
/* eslint-env jest */
import { imgSnapshotTest } from '../../helpers/util.js';
describe('Pie Chart', () => {
// beforeEach(()=>{
// cy.clock((new Date('2014-06-09')).getTime());
// });
['default', 'forest', 'dark', 'neutral'].forEach(theme=>{
describe(theme, () => {
it('should render a pie diagram', () => {
imgSnapshotTest(
`
pie title Sports in Sweden
"Bandy" : 40
"Ice-Hockey" : 80
"Football" : 90
`,
{theme}
);
cy.get('svg');
});
it('should render a flowchart diagram', () => {
imgSnapshotTest(
`
%%{init: { 'logLevel': 0, 'theme': '${theme}'} }%%
graph TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[/Another/]
C ==>|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
subgraph section
C
D
E
F
G
end
`,
{theme}
);
cy.get('svg');
});
it('should render a new flowchart diagram', () => {
imgSnapshotTest(
`
%%{init: { 'logLevel': 0, 'theme': '${theme}'} }%%
flowchart TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[Another]
C ==>|One| D[Laptop]
C x--x|Two| E[iPhone]
C o--o|Three| F[fa:fa-car Car]
subgraph section
C
D
E
F
G
end
`,
{theme}
);
cy.get('svg');
});
it('should render a sequence diagram', () => {
imgSnapshotTest(
`
%%{init: { 'logLevel': 0, 'theme': '${theme}'} }%%
sequenceDiagram
autonumber
par Action 1
Alice->>John: Hello John, how are you?
and Action 2
Alice->>Bob: Hello Bob, how are you?
end
Alice->>+John: Hello John, how are you?
Alice->>+John: John, can you hear me?
John-->>-Alice: Hi Alice, I can hear you!
Note right of John: John is perceptive
John-->>-Alice: I feel great!
loop Every minute
John-->Alice: Great!
end
`,
{theme}
);
cy.get('svg');
});
it('should render a class diagram', () => {
imgSnapshotTest(
`
%%{init: { 'logLevel': 0, 'theme': '${theme}'} }%%
classDiagram
Animal "*" <|-- "1" Duck
Animal "1" <|-- "10" Fish
Animal <|-- Zebra
Animal : +int age
Animal : +String gender
Animal: +isMammal()
Animal: +mate()
class Duck{
+String beakColor
+swim()
+quack()
}
class Fish{
-int sizeInFeet
-canEat()
}
class Zebra{
+bool is_wild
+run()
}
classA <|-- classB
classC *-- classD
classE o-- classF
classG <-- classH
classI -- classJ
classK <.. classL
classM <|.. classN
classO .. classP
classA --|> classB : Inheritance
classC --* classD : Composition
classE --o classF : Aggregation
classG --> classH : Association
classI -- classJ : Link(Solid)
classK ..> classL : Dependency
classM ..|> classN : Realization
classO .. classP : Link(Dashed)
`,
{theme}
);
cy.get('svg');
});
it('should render a state diagram', () => {
imgSnapshotTest(
`
%%{init: { 'logLevel': 0, 'theme': '${theme}'} }%%
stateDiagram
[*] --> Active
state Active {
[*] --> NumLockOff
NumLockOff --> NumLockOn : EvNumLockPressed
NumLockOn --> NumLockOff : EvNumLockPressed
--
[*] --> CapsLockOff
CapsLockOff --> CapsLockOn : EvCapsLockPressed
CapsLockOn --> CapsLockOff : EvCapsLockPressed
--
[*] --> ScrollLockOff
ScrollLockOff --> ScrollLockOn : EvCapsLockPressed
ScrollLockOn --> ScrollLockOff : EvCapsLockPressed
}
state SomethingElse {
A --> B
B --> A
}
Active --> SomethingElse
note right of SomethingElse : This is the note to the right.
`,
{theme}
);
cy.get('svg');
});
it('should render a state diagram (v2)', () => {
imgSnapshotTest(
`
%%{init: { 'logLevel': 0, 'theme': '${theme}'} }%%
stateDiagram-v2
[*] --> Active
state Active {
[*] --> NumLockOff
NumLockOff --> NumLockOn : EvNumLockPressed
NumLockOn --> NumLockOff : EvNumLockPressed
--
[*] --> CapsLockOff
CapsLockOff --> CapsLockOn : EvCapsLockPressed
CapsLockOn --> CapsLockOff : EvCapsLockPressed
--
[*] --> ScrollLockOff
ScrollLockOff --> ScrollLockOn : EvCapsLockPressed
ScrollLockOn --> ScrollLockOff : EvCapsLockPressed
}
state SomethingElse {
A --> B
B --> A
}
Active --> SomethingElse2
note right of SomethingElse2 : This is the note to the right.
`,
{theme}
);
cy.get('svg');
});
it('should render a er diagram', () => {
imgSnapshotTest(
`
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"
`,
{theme}
);
cy.get('svg');
});
it('should render a user journey diagram', () => {
imgSnapshotTest(
`
%%{init: { 'logLevel': 0, 'theme': '${theme}'} }%%
journey
title My working day
section Go to work
Make tea: 5: Me
Go upstairs: 3: Me
Do work: 1: Me, Cat
section Go home
Go downstairs: 5: Me
Sit down: 5: Me
`,
{theme}
);
cy.get('svg');
});
it('should render a gantt diagram', () => {
cy.clock((new Date('2014-01-06')).getTime());
imgSnapshotTest(
`
gantt
dateFormat :YYYY-MM-DD
title :Adding GANTT diagram functionality to mermaid
excludes :excludes the named dates/days from being included in a charted task..
section A section
Completed task :done, des1, 2014-01-06,2014-01-08
Active task :active, des2, 2014-01-09, 3d
Future task : des3, after des2, 5d
Future task2 : des4, after des3, 5d
section Critical tasks
Completed task in the critical line :crit, done, 2014-01-06,24h
Implement parser and jison :crit, done, after des1, 2d
Create tests for parser :crit, active, 3d
Future task in critical line :crit, 5d
Create tests for renderer :2d
Add to mermaid :1d
section Documentation
Describe gantt syntax :active, a1, after des1, 3d
Add gantt diagram to demo page :after a1 , 20h
Add another diagram to demo page :doc1, after a1 , 48h
section Last section
Describe gantt syntax :after doc1, 3d
Add gantt diagram to demo page :20h
Add another diagram to demo page :48h
`,
{theme}
);
cy.get('svg');
});
});
});
});

View File

@ -1,10 +1,61 @@
import mermaid from '../../dist/mermaid.core'
import mermaid from '../../dist/mermaid.core';
let code = `flowchart LR
Power_Supply --> Transmitter_A
Power_Supply --> Transmitter_B
Transmitter_A --> D
Transmitter_B --> D`;
let code2 = `gantt
dateFormat YYYY-MM-DD
title Adding GANTT diagram functionality to mermaid
section A section
Completed task :done, des1, 2014-01-06,2014-01-08
Active task :active, des2, 2014-01-09, 3d
Future task : des3, after des2, 5d
Future task2 : des4, after des3, 5d
section Critical tasks
Completed task in the critical line :crit, done, 2014-01-06,24h
Implement parser and jison :crit, done, after des1, 2d
Create tests for parser :crit, active, 3d
Future task in critical line :crit, 5d
Create tests for renderer :2d
Add to mermaid :1d`;
const code3 = `flowchart TD
A(<img scr='https://iconscout.com/ms-icon-310x310.png' width='20' height='20' />)
B(<b>Bold text!</b>)`;
if (location.href.match('test-html-escaping')) {
code = code3;
}
mermaid.initialize({
theme: 'forest',
gantt: { axisFormatter: [
['%Y-%m-%d', (d) => {
return d.getDay() === 1
}]
] }
})
theme: 'default',
// fontFamily: '"Lucida Console", Monaco, monospace',
startOnLoad: false,
securityLevel: 'loose',
flowchart: {
htmlLabels: true
},
gantt: {
axisFormatter: [
[
'%Y-%m-%d',
d => {
return d.getDay() === 1;
}
]
]
}
});
mermaid.render(
'the-id-of-the-svg',
code,
svg => {
console.log(svg);
const elem = document.querySelector('#graph-to-be');
elem.innerHTML = svg;
}
// ,document.querySelector('#tmp')
);

View File

@ -0,0 +1,66 @@
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap" rel="stylesheet">
<style>
body {
background: rgb(221, 208, 208);
/*background:#333;*/
font-family: 'Arial';
}
h1 { color: white;}
.mermaid2 {
display: none;
}
</style>
</head>
<body>
<h1>info below</h1>
<div class="mermaid" style="width: 100%; height: 20%;">
classDiagram-v2
class BankAccount{
+String owner
+BigDecimal balance
+deposit(amount) bool
+withdrawl(amount) int
}
classA --|> classB : Inheritance
classC --* classD : Composition
classE --o classF : Aggregation
classG --> classH : Association
classI -- classJ : Link(Solid)
classK ..> classL : Dependency
classM ..|> classN : Realization
classO .. classP : Link(Dashed)
classA : +attr1
classA : attr2
classA : method1()
&lt;&lt;interface&gt;&gt; classB
classB : method2() int
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
theme: 'default',
// arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 0,
flowchart: { curve: 'linear', "htmlLabels": false },
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50, showSequenceNumbers: true },
// sequenceDiagram: { actorMargin: 300 } // deprecated
fontFamily: '"arial", sans-serif',
curve: 'linear',
securityLevel: 'loose'
});
function callback(){alert('It worked');}
</script>
</body>
</html>

View File

@ -4,15 +4,16 @@
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
rel="stylesheet"
/>
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap" rel="stylesheet">
<style>
body {
/* background: rgb(221, 208, 208); */
background:#333;
/* background:#333; */
font-family: 'Arial';
}
h1 { color: white;}
h1 { color: grey;}
.mermaid2 {
display: none;
}
@ -20,240 +21,84 @@
</head>
<body>
<h1>info below</h1>
<div class="mermaid" style="width: 100%; height: 20%;">
flowchart LR
user1[fa:fa-user User 1] -- edit -> folder
</div>
<div class="flex">
<div class="mermaid2" style="width: 50%; height: 20%;">
flowchart LR
A{{A}}-- apa -->B{{B}};
click A callback "Tooltip"
click B "http://www.github.com" "This is a link"
</div>
<div class="mermaid2" style="width: 50%; height: 20%;">
graph LR
A{{A}}--apa-->B{{B}};
</div>
<div class="mermaid2" style="width: 50%; height: 20%;">
stateDiagram-v2
[*]-->TV
state TV {
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 --> [*]
}
</div>
<div class="mermaid2" style="width: 100%; height: 100%;">
stateDiagram-v2
[*] --> Still
Still --> [*]
Still --> Moving
Moving --> Still
Moving --> Crash
Crash --> [*]
</div>
<div class="mermaid2" style="width: 100%; height: 100%;">
stateDiagram-v2
[*] --> First
First --> Third
First --> sec
state First {
[*] --> fir
fir --> [*]
}
state Second {
[*] --> sec
sec --> [*]
}
state Third {
[*] --> thi
thi --> [*]
}
thi --> sec
</div>
<div class="mermaid2" style="width: 100%; height: 100%;">
flowchart TD
subgraph A
a
flowchart BT
subgraph two
b1
end
subgraph B
b
subgraph three
c1-->c2
end
subgraph C
subgraph D
d
c1 --apa apa apa--> b1
two --> c2
</div>
<div class="mermaid" style="width: 50%; height: 200px;">
sequenceDiagram
Alice->>Bob:Extremely utterly long line of longness which had preivously overflown the actor box as it is much longer than what it should be
Bob->>Alice: I'm short though
</div>
<div class="mermaid" style="width: 50%; height: 200px;">
%%{init: {'securityLevel': 'loose'}}%%
graph TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{{Let me think...<br />Do I want something for work,<br />something to spend every free second with,<br />or something to get around?}}
C -->|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[Car]
click A "index.html#link-clicked" "link test"
click B callback "click test"
classDef someclass fill:#f96;
class A someclass;
class C someclass;
</div>
<div class="mermaid2" style="width: 50%; height: 200px;">
flowchart BT
subgraph a
b1 -- ok --> b2
end
end
A -- oAo --o B
A --> C
</div>
<div class="mermaid2" style="width: 100%; height: 100%;">
flowchart TD
subgraph A
a
end
subgraph B
b
end
c-->A
c-->B
</div>
<div class="mermaid2" style="width: 100%; height: 100%;">
a -- sert --> c
c --> d
b1 --> d
a --asd123 --> d
</div>
<div class="mermaid2" style="width: 50%; height: 20%;">
stateDiagram-v2
[*] --> First
First --> Second
First --> Third
state A {
B1 --> B2: ok
}
A --> C: sert
C --> D
B1 --> D
A --> D: asd123
</div>
</div>
<div class="mermaid" style="width: 50%; height: 20%;">
state First {
[*] --> fir
fir --> [*]
}
state Second {
[*] --> sec
sec --> [*]
}
state Third {
[*] --> thi
thi --> [*]
}
</div>
<div class="mermaid2" style="width: 100%; height: 100%;">
stateDiagram-v2
[*]-->TV
state TV {
[*] --> Off: Off to start with
On --> Off : Turn off
Off --> On : Turn on
}
TV--> Console
state Console {
[*] --> Off2: Off to start with
On2--> Off2 : Turn off
Off2 --> On2 : Turn on
On2-->Playing
state Playing {
Alive --> Dead
Dead-->Alive
}
}
classDiagram
Customer "1" --> "*" Ticket
Student "1" --> "1..*" Course
Galaxy --> "many" Star : Contains
</div>
<div style="display: flex;flex-direction:column;width: 100%; height: 100%">
<div class="mermaid2" style="width: 100%; height: 100%;">
stateDiagram-v2
state apa {
[*] --> Still
Still --> [*]
Still --> Moving
Moving --> Still
Moving --> Crash
Crash --> [*]
}
</div>
<div class="mermaid2" style="width: 100%; height: 100%">
flowchart TB
a --> b
subgraph id1 [Test]
a --apa--> c
b
c-->b
b-->H
end
G-->H
G-->id1
id1 --> I
I --> G
</div>
<div class="mermaid2" style="width: 100%; height: 100%">
flowchart RL
a --> b
subgraph id1 [Test]
a --apa--> c
b
c-->b
b-->H
end
G-->H
G-->id1
id1 --> I
I --> G
</div>
<div class="mermaid2" style="width: 100%; height: 100%">
flowchart RL
subgraph id1 [Test]
a
end
b-->id1
</div>
<div class="mermaid2" style="width: 100%; height: 100%">
flowchart RL
subgraph id1 [Test1]
a
end
subgraph id2 [Test2]
b
end
a --> id2
a --> b
b-->id1
id1 --> id2
</div>
new:
<div class="mermaid2" style="width: 100%; height: 100%">
flowchart LR
a <--> b
b o--o c
c x--x d
a21([In the box]) --> b2
b2((b2)) --o c2
c2(c2) --x d2 --> id1{{This is the text in the box}} --> A[(cylindrical<br />shape<br />test)]
</div>
old:
<div class="mermaid2" style="width: 100%; height: 100%">
graph LR
a((a)) --> b --> id1{{This is the text in the box}}
A[(cylindrical<br />shape<br />test)]
</div>
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
theme: 'dark',
// theme: 'dark',
// arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 0,
flowchart: { curve: 'linear', "htmlLabels": false },
flowchart: { curve: 'cardinal', "htmlLabels": false },
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50, showSequenceNumbers: true },
// sequenceDiagram: { actorMargin: 300 } // deprecated
fontFamily: '"arial", sans-serif',
curve: 'linear',
securityLevel: 'loose'
curve: 'cardinal',
securityLevel: 'strict'
});
function callback(){alert('It worked');}
</script>

View File

@ -1,12 +1,16 @@
<html>
<head>
<meta charset="utf-8"/>
<!-- <meta charset="iso-8859-15"/> -->
<script src="/e2e.js"></script>
<link href="https://fonts.googleapis.com/css?family=Mansalva&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap" rel="stylesheet">
<!-- <link href="https://fonts.googleapis.com/css?family=Mansalva&display=swap" rel="stylesheet" /> -->
<!-- <link href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap" rel="stylesheet"> -->
<style>
body {
/* font-family: 'Mansalva', cursive;*/
font-family: 'Mansalva', cursive;
/* font-family: 'Mansalva', cursive; */
/* font-family: '"Noto Sans SC", sans-serif'; */
/* font-family: "trebuchet ms", verdana, arial; */
}
/* .mermaid-main-font {
font-family: "trebuchet ms", verdana, arial;
@ -34,6 +38,7 @@
// fontFamily: '\"trebuchet ms\", verdana, arial;'
// fontFamily: '"Comic Sans MS", "Comic Sans", cursive'
// fontFamily: '"Mansalva", cursive',
// fontFamily: '"Noto Sans SC", sans-serif'
fontFamily: '"Noto Sans SC", sans-serif'
});
</script>

View File

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Mermaid Quick Test Page</title>
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=">
</head>
<body>
<div id="graph">
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.init({ startOnLoad: false });
mermaid.mermaidAPI.initialize();
try{
mermaid.mermaidAPI.render("graphDiv",
`>`);
} catch(e){}
mermaid.mermaidAPI.render("graphDiv",
`graph LR\n a --> b`, html => {
document.getElementById('graph').innerHTML=html;
});
</script>
</body>
</html>

View File

@ -0,0 +1,227 @@
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
rel="stylesheet"
/>
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap" rel="stylesheet">
<style>
body {
/* background: rgb(221, 208, 208); */
background: #f4f4f4;
/* background: #0c0c0c; */
font-family: 'Arial';
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
h1 { color: grey;}
.mermaid2 {
display: none;
}
.height {
min-height: 600px;
height: 600px;
}
.height2 {
min-height: 600px;
height: 1300px;
}
.width {
width: 33%;
border: 1px solid blue;
padding: 10px;
}
</style>
</head>
<body>
<h1>Showcases of diagrams</h1>
<div class="flex flex-wrap">
<div class="mermaid width height">
%%{init2: {'securityLevel': 'loose', 'theme':'base'}}%%
graph TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[/Another/]
C ==>|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
subgraph section
C
D
E
F
G
end
</div>
<div class="mermaid width height">
%%{init2: {'securityLevel': 'loose', 'theme':'base'}}%%
flowchart TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[Another]
C ==>|One| D[Laptop]
C x--x|Two| E[iPhone]
C o--o|Three| F[fa:fa-car Car]
subgraph section
C
D
E
F
G
end
</div>
<div class="mermaid width height" >
%%{init2: {'securityLevel': 'loose', 'theme':'base'}}%%
sequenceDiagram
autonumber
par Action 1
Alice->>John: Hello John, how are you?
and Action 2
Alice->>Bob: Hello Bob, how are you?
end
Alice->>+John: Hello John, how are you?
Alice->>+John: John, can you hear me?
John-->>-Alice: Hi Alice, I can hear you!
Note right of John: John is perceptive
John-->>-Alice: I feel great!
loop Every minute
John-->Alice: Great!
end
</div>
<div class="mermaid width height">
gantt
dateFormat :YYYY-MM-DD
title Adding GANTT diagram functionality to mermaid
excludes :excludes the named dates/days from being included in a charted task..
section A section
Completed task :done, des1, 2014-01-06,2014-01-08
Active task :active, des2, 2014-01-09, 3d
Future task : des3, after des2, 5d
Future task2 : des4, after des3, 5d
section Critical tasks
Completed task in the critical line :crit, done, 2014-01-06,24h
Implement parser and jison :crit, done, after des1, 2d
Create tests for parser :crit, active, 3d
Future task in critical line :crit, 5d
Create tests for renderer :2d
Add to mermaid :1d
section Documentation
Describe gantt syntax :active, a1, after des1, 3d
Add gantt diagram to demo page :after a1 , 20h
Add another diagram to demo page :doc1, after a1 , 48h
section Last section
Describe gantt syntax :after doc1, 3d
Add gantt diagram to demo page :20h
Add another diagram to demo page :48h
</div>
<div class="mermaid width height2">
%%{init2: {'securityLevel': 'loose', 'theme':'base'}}%%
stateDiagram
[*] --> Active
state Active {
[*] --> NumLockOff
NumLockOff --> NumLockOn : EvNumLockPressed
NumLockOn --> NumLockOff : EvNumLockPressed
--
[*] --> CapsLockOff
CapsLockOff --> CapsLockOn : EvCapsLockPressed
CapsLockOn --> CapsLockOff : EvCapsLockPressed
--
[*] --> ScrollLockOff
ScrollLockOff --> ScrollLockOn : EvCapsLockPressed
ScrollLockOn --> ScrollLockOff : EvCapsLockPressed
}
state SomethingElse {
A --> B
B --> A
}
Active --> SomethingElse
note right of SomethingElse : This is the note to the right.
SomethingElse --> [*]
</div>
<div class="mermaid width height2">
%%{init2: {'securityLevel': 'loose', 'theme':'base'}}%%
stateDiagram-v2
[*] --> Active
state Active {
[*] --> NumLockOff
NumLockOff --> NumLockOn : EvNumLockPressed
NumLockOn --> NumLockOff : EvNumLockPressed
--
[*] --> CapsLockOff
CapsLockOff --> CapsLockOn : EvCapsLockPressed
CapsLockOn --> CapsLockOff : EvCapsLockPressed
--
[*] --> ScrollLockOff
ScrollLockOff --> ScrollLockOn : EvCapsLockPressed
ScrollLockOn --> ScrollLockOff : EvCapsLockPressed
}
state SomethingElse {
A --> B
B --> A
}
Active --> SomethingElse2
note right of SomethingElse2 : This is the note to the right.
SomethingElse2 --> [*]
</div>
<div class="mermaid width height2">
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"
</div>
<div class="mermaid width height">
journey
title My working day
section Go to work
Make tea: 5: Me
Go upstairs: 3: Me
Do work: 1: Me, Cat
section Go home
Go downstairs: 5: Me
Sit down: 5: Me
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
theme: 'base',
themeVariables: { primaryColor: '#ff0000'},
// arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 0,
flowchart: { curve: 'cardinal', "htmlLabels": false },
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50, showSequenceNumbers: true },
// sequenceDiagram: { actorMargin: 300 } // deprecated
fontFamily: '"arial", sans-serif',
curve: 'cardinal',
securityLevel: 'strict'
});
function callback(){alert('It worked');}
</script>
</body>
</html>

View File

@ -0,0 +1,215 @@
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
rel="stylesheet"
/>
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap" rel="stylesheet">
<style>
body {
/* background: rgb(221, 208, 208); */
background:#333;
font-family: 'Arial';
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
h1 { color: grey;}
.mermaid2 {
display: none;
}
.height {
min-height: 600px;
height: 600px;
}
.height2 {
min-height: 600px;
height: 1300px;
}
.width {
width: 33%;
border: 1px solid blue;
padding: 10px;
}
</style>
</head>
<body>
<h1>Showcases of diagrams</h1>
<div class="flex flex-wrap">
<div class="mermaid width height">
%%{init: {'theme': 'dark'}}%%
graph TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[/Another/]
C ==>|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
subgraph section
C
D
E
F
G
end
</div>
<div class="mermaid width height">
flowchart TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[Another]
C ==>|One| D[Laptop]
C x--x|Two| E[iPhone]
C o--o|Three| F[fa:fa-car Car]
subgraph section
C
D
E
F
G
end
</div>
<div class="mermaid width height" >
sequenceDiagram
autonumber
par Action 1
Alice->>John: Hello John, how are you?
and Action 2
Alice->>Bob: Hello Bob, how are you?
end
Alice->>+John: Hello John, how are you?
Alice->>+John: John, can you hear me?
John-->>-Alice: Hi Alice, I can hear you!
Note right of John: John is perceptive
John-->>-Alice: I feel great!
loop Every minute
John-->Alice: Great!
end
</div>
<div class="mermaid width height">
gantt
dateFormat :YYYY-MM-DD
title Adding GANTT diagram functionality to mermaid
excludes :excludes the named dates/days from being included in a charted task..
section A section
Completed task :done, des1, 2014-01-06,2014-01-08
Active task :active, des2, 2014-01-09, 3d
Future task : des3, after des2, 5d
Future task2 : des4, after des3, 5d
section Critical tasks
Completed task in the critical line :crit, done, 2014-01-06,24h
Implement parser and jison :crit, done, after des1, 2d
Create tests for parser :crit, active, 3d
Future task in critical line :crit, 5d
Create tests for renderer :2d
Add to mermaid :1d
section Documentation
Describe gantt syntax :active, a1, after des1, 3d
Add gantt diagram to demo page :after a1 , 20h
Add another diagram to demo page :doc1, after a1 , 48h
section Last section
Describe gantt syntax :after doc1, 3d
Add gantt diagram to demo page :20h
Add another diagram to demo page :48h
</div>
<div class="mermaid width height2">
stateDiagram
[*] --> Active
state Active {
[*] --> NumLockOff
NumLockOff --> NumLockOn : EvNumLockPressed
NumLockOn --> NumLockOff : EvNumLockPressed
--
[*] --> CapsLockOff
CapsLockOff --> CapsLockOn : EvCapsLockPressed
CapsLockOn --> CapsLockOff : EvCapsLockPressed
--
[*] --> ScrollLockOff
ScrollLockOff --> ScrollLockOn : EvCapsLockPressed
ScrollLockOn --> ScrollLockOff : EvCapsLockPressed
}
state SomethingElse {
A --> B
B --> A
}
Active --> SomethingElse
note right of SomethingElse : This is the note to the right.
</div>
<div class="mermaid width height2">
stateDiagram-v2
[*] --> Active
state Active {
[*] --> NumLockOff
NumLockOff --> NumLockOn : EvNumLockPressed
NumLockOn --> NumLockOff : EvNumLockPressed
--
[*] --> CapsLockOff
CapsLockOff --> CapsLockOn : EvCapsLockPressed
CapsLockOn --> CapsLockOff : EvCapsLockPressed
--
[*] --> ScrollLockOff
ScrollLockOff --> ScrollLockOn : EvCapsLockPressed
ScrollLockOn --> ScrollLockOff : EvCapsLockPressed
}
state SomethingElse {
A --> B
B --> A
}
Active --> SomethingElse2
note right of SomethingElse2 : This is the note to the right.
</div>
<div class="mermaid width height2">
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"
</div>
<div class="mermaid width height">
journey
title My working day
section Go to work
Make tea: 5: Me
Go upstairs: 3: Me
Do work: 1: Me, Cat
section Go home
Go downstairs: 5: Me
Sit down: 5: Me
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
theme: 'forest',
// arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 0,
flowchart: { curve: 'cardinal', "htmlLabels": true },
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50, showSequenceNumbers: true },
// sequenceDiagram: { actorMargin: 300 } // deprecated
fontFamily: '"arial", sans-serif',
curve: 'cardinal',
securityLevel: 'strict'
});
function callback(){alert('It worked');}
</script>
</body>
</html>

View File

@ -0,0 +1,214 @@
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
rel="stylesheet"
/>
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap" rel="stylesheet">
<style>
body {
/* background: rgb(221, 208, 208); */
/* background:#333; */
font-family: 'Arial';
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
h1 { color: grey;}
.mermaid2 {
display: none;
}
.height {
min-height: 600px;
height: 600px;
}
.height2 {
min-height: 600px;
height: 1300px;
}
.width {
width: 33%;
border: 1px solid blue;
padding: 10px;
}
</style>
</head>
<body>
<h1>Showcases of diagrams</h1>
<div class="flex flex-wrap">
<div class="mermaid width height">
graph TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[/Another/]
C ==>|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
subgraph section
C
D
E
F
G
end
</div>
<div class="mermaid width height">
flowchart TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[Another]
C ==>|One| D[Laptop]
C x--x|Two| E[iPhone]
C o--o|Three| F[fa:fa-car Car]
subgraph section
C
D
E
F
G
end
</div>
<div class="mermaid width height" >
sequenceDiagram
autonumber
par Action 1
Alice->>John: Hello John, how are you?
and Action 2
Alice->>Bob: Hello Bob, how are you?
end
Alice->>+John: Hello John, how are you?
Alice->>+John: John, can you hear me?
John-->>-Alice: Hi Alice, I can hear you!
Note right of John: John is perceptive
John-->>-Alice: I feel great!
loop Every minute
John-->Alice: Great!
end
</div>
<div class="mermaid width height">
gantt
dateFormat :YYYY-MM-DD
title Adding GANTT diagram functionality to mermaid
excludes :excludes the named dates/days from being included in a charted task..
section A section
Completed task :done, des1, 2014-01-06,2014-01-08
Active task :active, des2, 2014-01-09, 3d
Future task : des3, after des2, 5d
Future task2 : des4, after des3, 5d
section Critical tasks
Completed task in the critical line :crit, done, 2014-01-06,24h
Implement parser and jison :crit, done, after des1, 2d
Create tests for parser :crit, active, 3d
Future task in critical line :crit, 5d
Create tests for renderer :2d
Add to mermaid :1d
section Documentation
Describe gantt syntax :active, a1, after des1, 3d
Add gantt diagram to demo page :after a1 , 20h
Add another diagram to demo page :doc1, after a1 , 48h
section Last section
Describe gantt syntax :after doc1, 3d
Add gantt diagram to demo page :20h
Add another diagram to demo page :48h
</div>
<div class="mermaid width height2">
stateDiagram
[*] --> Active
state Active {
[*] --> NumLockOff
NumLockOff --> NumLockOn : EvNumLockPressed
NumLockOn --> NumLockOff : EvNumLockPressed
--
[*] --> CapsLockOff
CapsLockOff --> CapsLockOn : EvCapsLockPressed
CapsLockOn --> CapsLockOff : EvCapsLockPressed
--
[*] --> ScrollLockOff
ScrollLockOff --> ScrollLockOn : EvCapsLockPressed
ScrollLockOn --> ScrollLockOff : EvCapsLockPressed
}
state SomethingElse {
A --> B
B --> A
}
Active --> SomethingElse
note right of SomethingElse : This is the note to the right.
</div>
<div class="mermaid width height2">
stateDiagram-v2
[*] --> Active
state Active {
[*] --> NumLockOff
NumLockOff --> NumLockOn : EvNumLockPressed
NumLockOn --> NumLockOff : EvNumLockPressed
--
[*] --> CapsLockOff
CapsLockOff --> CapsLockOn : EvCapsLockPressed
CapsLockOn --> CapsLockOff : EvCapsLockPressed
--
[*] --> ScrollLockOff
ScrollLockOff --> ScrollLockOn : EvCapsLockPressed
ScrollLockOn --> ScrollLockOff : EvCapsLockPressed
}
state SomethingElse {
A --> B
B --> A
}
Active --> SomethingElse2
note right of SomethingElse2 : This is the note to the right.
</div>
<div class="mermaid width height2">
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"
</div>
<div class="mermaid width height">
journey
title My working day
section Go to work
Make tea: 5: Me
Go upstairs: 3: Me
Do work: 1: Me, Cat
section Go home
Go downstairs: 5: Me
Sit down: 5: Me
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
// theme: 'dark',
// arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 0,
flowchart: { curve: 'cardinal', "htmlLabels": false },
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50, showSequenceNumbers: true },
// sequenceDiagram: { actorMargin: 300 } // deprecated
fontFamily: '"arial", sans-serif',
curve: 'cardinal',
securityLevel: 'strict'
});
function callback(){alert('It worked');}
</script>
</body>
</html>

View File

@ -0,0 +1,215 @@
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
rel="stylesheet"
/>
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap" rel="stylesheet">
<style>
body {
/* background: rgb(221, 208, 208); */
/* background:#333; */
font-family: 'Arial';
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
h1 { color: grey;}
.mermaid2 {
display: none;
}
.height {
min-height: 600px;
height: 600px;
}
.height2 {
min-height: 600px;
height: 1300px;
}
.width {
width: 33%;
border: 1px solid blue;
padding: 10px;
}
</style>
</head>
<body>
<h1>Showcases of diagrams</h1>
<div class="flex flex-wrap">
<div class="mermaid width height">
%%{init: {'theme': 'forest'}}%%
graph TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[/Another/]
C ==>|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
subgraph section
C
D
E
F
G
end
</div>
<div class="mermaid width height">
flowchart TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[Another]
C ==>|One| D[Laptop]
C x--x|Two| E[iPhone]
C o--o|Three| F[fa:fa-car Car]
subgraph section
C
D
E
F
G
end
</div>
<div class="mermaid width height" >
sequenceDiagram
autonumber
par Action 1
Alice->>John: Hello John, how are you?
and Action 2
Alice->>Bob: Hello Bob, how are you?
end
Alice->>+John: Hello John, how are you?
Alice->>+John: John, can you hear me?
John-->>-Alice: Hi Alice, I can hear you!
Note right of John: John is perceptive
John-->>-Alice: I feel great!
loop Every minute
John-->Alice: Great!
end
</div>
<div class="mermaid width height">
gantt
dateFormat :YYYY-MM-DD
title Adding GANTT diagram functionality to mermaid
excludes :excludes the named dates/days from being included in a charted task..
section A section
Completed task :done, des1, 2014-01-06,2014-01-08
Active task :active, des2, 2014-01-09, 3d
Future task : des3, after des2, 5d
Future task2 : des4, after des3, 5d
section Critical tasks
Completed task in the critical line :crit, done, 2014-01-06,24h
Implement parser and jison :crit, done, after des1, 2d
Create tests for parser :crit, active, 3d
Future task in critical line :crit, 5d
Create tests for renderer :2d
Add to mermaid :1d
section Documentation
Describe gantt syntax :active, a1, after des1, 3d
Add gantt diagram to demo page :after a1 , 20h
Add another diagram to demo page :doc1, after a1 , 48h
section Last section
Describe gantt syntax :after doc1, 3d
Add gantt diagram to demo page :20h
Add another diagram to demo page :48h
</div>
<div class="mermaid width height2">
stateDiagram
[*] --> Active
state Active {
[*] --> NumLockOff
NumLockOff --> NumLockOn : EvNumLockPressed
NumLockOn --> NumLockOff : EvNumLockPressed
--
[*] --> CapsLockOff
CapsLockOff --> CapsLockOn : EvCapsLockPressed
CapsLockOn --> CapsLockOff : EvCapsLockPressed
--
[*] --> ScrollLockOff
ScrollLockOff --> ScrollLockOn : EvCapsLockPressed
ScrollLockOn --> ScrollLockOff : EvCapsLockPressed
}
state SomethingElse {
A --> B
B --> A
}
Active --> SomethingElse
note right of SomethingElse : This is the note to the right.
</div>
<div class="mermaid width height2">
stateDiagram-v2
[*] --> Active
state Active {
[*] --> NumLockOff
NumLockOff --> NumLockOn : EvNumLockPressed
NumLockOn --> NumLockOff : EvNumLockPressed
--
[*] --> CapsLockOff
CapsLockOff --> CapsLockOn : EvCapsLockPressed
CapsLockOn --> CapsLockOff : EvCapsLockPressed
--
[*] --> ScrollLockOff
ScrollLockOff --> ScrollLockOn : EvCapsLockPressed
ScrollLockOn --> ScrollLockOff : EvCapsLockPressed
}
state SomethingElse {
A --> B
B --> A
}
Active --> SomethingElse2
note right of SomethingElse2 : This is the note to the right.
</div>
<div class="mermaid width height2">
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"
</div>
<div class="mermaid width height">
journey
title My working day
section Go to work
Make tea: 5: Me
Go upstairs: 3: Me
Do work: 1: Me, Cat
section Go home
Go downstairs: 5: Me
Sit down: 5: Me
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
theme: 'forest',
// arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 0,
flowchart: { curve: 'cardinal', "htmlLabels": false },
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50, showSequenceNumbers: true },
// sequenceDiagram: { actorMargin: 300 } // deprecated
fontFamily: '"arial", sans-serif',
curve: 'cardinal',
securityLevel: 'strict'
});
function callback(){alert('It worked');}
</script>
</body>
</html>

View File

@ -0,0 +1,215 @@
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
rel="stylesheet"
/>
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap" rel="stylesheet">
<style>
body {
/* background: rgb(221, 208, 208); */
/* background:#333; */
font-family: 'Arial';
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
h1 { color: grey;}
.mermaid2 {
display: none;
}
.height {
min-height: 600px;
height: 600px;
}
.height2 {
min-height: 600px;
height: 1300px;
}
.width {
width: 33%;
border: 1px solid blue;
padding: 10px;
}
</style>
</head>
<body>
<h1>Showcases of diagrams</h1>
<div class="flex flex-wrap">
<div class="mermaid width height">
%%{init: {'theme': 'neutral'}}%%
graph TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[/Another/]
C ==>|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
subgraph section
C
D
E
F
G
end
</div>
<div class="mermaid width height">
flowchart TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[Another]
C ==>|One| D[Laptop]
C x--x|Two| E[iPhone]
C o--o|Three| F[fa:fa-car Car]
subgraph section
C
D
E
F
G
end
</div>
<div class="mermaid width height" >
sequenceDiagram
autonumber
par Action 1
Alice->>John: Hello John, how are you?
and Action 2
Alice->>Bob: Hello Bob, how are you?
end
Alice->>+John: Hello John, how are you?
Alice->>+John: John, can you hear me?
John-->>-Alice: Hi Alice, I can hear you!
Note right of John: John is perceptive
John-->>-Alice: I feel great!
loop Every minute
John-->Alice: Great!
end
</div>
<div class="mermaid width height">
gantt
dateFormat :YYYY-MM-DD
title Adding GANTT diagram functionality to mermaid
excludes :excludes the named dates/days from being included in a charted task..
section A section
Completed task :done, des1, 2014-01-06,2014-01-08
Active task :active, des2, 2014-01-09, 3d
Future task : des3, after des2, 5d
Future task2 : des4, after des3, 5d
section Critical tasks
Completed task in the critical line :crit, done, 2014-01-06,24h
Implement parser and jison :crit, done, after des1, 2d
Create tests for parser :crit, active, 3d
Future task in critical line :crit, 5d
Create tests for renderer :2d
Add to mermaid :1d
section Documentation
Describe gantt syntax :active, a1, after des1, 3d
Add gantt diagram to demo page :after a1 , 20h
Add another diagram to demo page :doc1, after a1 , 48h
section Last section
Describe gantt syntax :after doc1, 3d
Add gantt diagram to demo page :20h
Add another diagram to demo page :48h
</div>
<div class="mermaid width height2">
stateDiagram
[*] --> Active
state Active {
[*] --> NumLockOff
NumLockOff --> NumLockOn : EvNumLockPressed
NumLockOn --> NumLockOff : EvNumLockPressed
--
[*] --> CapsLockOff
CapsLockOff --> CapsLockOn : EvCapsLockPressed
CapsLockOn --> CapsLockOff : EvCapsLockPressed
--
[*] --> ScrollLockOff
ScrollLockOff --> ScrollLockOn : EvCapsLockPressed
ScrollLockOn --> ScrollLockOff : EvCapsLockPressed
}
state SomethingElse {
A --> B
B --> A
}
Active --> SomethingElse
note right of SomethingElse : This is the note to the right.
</div>
<div class="mermaid width height2">
stateDiagram-v2
[*] --> Active
state Active {
[*] --> NumLockOff
NumLockOff --> NumLockOn : EvNumLockPressed
NumLockOn --> NumLockOff : EvNumLockPressed
--
[*] --> CapsLockOff
CapsLockOff --> CapsLockOn : EvCapsLockPressed
CapsLockOn --> CapsLockOff : EvCapsLockPressed
--
[*] --> ScrollLockOff
ScrollLockOff --> ScrollLockOn : EvCapsLockPressed
ScrollLockOn --> ScrollLockOff : EvCapsLockPressed
}
state SomethingElse {
A --> B
B --> A
}
Active --> SomethingElse2
note right of SomethingElse2 : This is the note to the right.
</div>
<div class="mermaid width height2">
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"
</div>
<div class="mermaid width height">
journey
title My working day
section Go to work
Make tea: 5: Me
Go upstairs: 3: Me
Do work: 1: Me, Cat
section Go home
Go downstairs: 5: Me
Sit down: 5: Me
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
theme: 'neutral',
// arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 0,
flowchart: { curve: 'cardinal', "htmlLabels": false },
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50, showSequenceNumbers: true },
// sequenceDiagram: { actorMargin: 300 } // deprecated
fontFamily: '"arial", sans-serif',
curve: 'cardinal',
securityLevel: 'strict'
});
function callback(){alert('It worked');}
</script>
</body>
</html>

View File

@ -0,0 +1,141 @@
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
rel="stylesheet"
/>
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap" rel="stylesheet">
<style>
body {
/* background: rgb(221, 208, 208); */
/* background:#333; */
font-family: 'Arial';
}
h1 { color: grey;}
.mermaid2 {
display: none;
}
.someClass > * {
/* fill: red !important; */
}
</style>
</head>
<body>
<h1>info below</h1>
<div class="flex flex-wrap">
<div class="mermaid" style="width: 50%; height: 20%;">
%%{init: { 'logLevel': 0, 'theme': 'default'} }%%
graph TD
A[Default] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[/Another/]
C ==>|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
subgraph section
C
D
E
F
G
end
</div>
<div class="mermaid" style="width: 50%; height: 20%;">
%%{init: { 'logLevel': 1, 'theme': 'forest'} }%%
graph TD
A[Forest] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[/Another/]
C ==>|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
subgraph section
C
D
E
F
G
end
</div>
<div class="mermaid" style="width: 50%; height: 20%;">
%%{init: { 'logLevel': 1, 'theme': 'neutral'} }%%
graph TD
A[Neutral] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[/Another/]
C ==>|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
subgraph section
C
D
E
F
G
end
</div>
<div class="mermaid" style="background: #3f3f3f; width: 50%; height: 20%;">
%%{init: { 'logLevel': 1, 'theme': 'dark'} }%%
graph TD
A[Dark] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[/Another/]
C ==>|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
subgraph section
C
D
E
F
G
end
</div>
<div class="mermaid" style="background: #3f3f3f; width: 50%; height: 20%;">
%%{init: { 'logLevel': 1} }%%
graph TD
A[None set] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[/Another/]
C ==>|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
subgraph section
C
D
E
F
G
end
</div>
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
// theme: 'dark',
// theme: 'dark',
// arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 0,
flowchart: { useMaxWidth: true },
graph: { curve: 'cardinal', "htmlLabels": false },
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50, showSequenceNumbers: true },
// sequenceDiagram: { actorMargin: 300 } // deprecated
fontFamily: '"arial", sans-serif',
curve: 'cardinal',
securityLevel: 'strict',
});
function callback(){alert('It worked');}
</script>
</body>
</html>

View File

@ -12,7 +12,9 @@ const contentLoaded = function() {
pos = pos + 7;
const graphBase64 = document.location.href.substr(pos);
const graphObj = JSON.parse(Base64.decode(graphBase64));
// const graph = 'hello'
if (graphObj.mermaid && graphObj.mermaid.theme === 'dark') {
document.body.style.background = '#3f3f3f';
}
console.log(graphObj);
if (Array.isArray(graphObj.code)) {
const numCodes = graphObj.code.length;
@ -30,6 +32,7 @@ const contentLoaded = function() {
div.innerHTML = graphObj.code;
document.getElementsByTagName('body')[0].appendChild(div);
}
global.mermaid.initialize(graphObj.mermaid);
global.mermaid.init();
}

View File

@ -1,22 +1,17 @@
<!doctype html>
<html>
<head>
<style>
/* .mermaid {
font-family: "trebuchet ms", verdana, arial;;
} */
/* .mermaid {
font-family: 'arial';
} */
</style>
</head>
<body>
<div class="mermaid">
graph LR
A-->B
</div>
<div class="mermaid">
gantt
title A Gantt Diagram
dateFormat YYYY-MM-DD
section Section
A task :a1, 2014-01-01, 30d
Another task :after a1 , 20d
section Another
Task in sec :2014-01-12 , 12d
another task : 24d
</div>
<div id="graph-to-be"></div>
<script src="./bundle-test.js" charset="utf-8"></script>
</body>

7889
dist/mermaid.core.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

11809
dist/mermaid.js vendored

File diff suppressed because one or more lines are too long

2
dist/mermaid.js.map vendored

File diff suppressed because one or more lines are too long

20
dist/mermaid.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

202
docs/8.6.0_docs.md Normal file
View File

@ -0,0 +1,202 @@
# Version 8.6.0 Changes
**Edit this Page** [![N|Solid](./img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/8.6.0_docs.md)
## [New Mermaid Live-Editor Beta](https://mermaid-js.github.io/docs/mermaid-live-editor-beta/#/edit/eyJjb2RlIjoiJSV7aW5pdDoge1widGhlbWVcIjogXCJmb3Jlc3RcIiwgXCJsb2dMZXZlbFwiOiAxIH19JSVcbmdyYXBoIFREXG4gIEFbQ2hyaXN0bWFzXSAtLT58R2V0IG1vbmV5fCBCKEdvIHNob3BwaW5nKVxuICBCIC0tPiBDe0xldCBtZSB0aGlua31cbiAgQyAtLT58T25lfCBEW0xhcHRvcF1cbiAgQyAtLT58VHdvfCBFW2lQaG9uZV1cbiAgQyAtLT58VGhyZWV8IEZbZmE6ZmEtY2FyIENhcl1cblx0XHQiLCJtZXJtYWlkIjp7InRoZW1lIjoiZGFyayJ9fQ)
## [CDN](https://unpkg.com/mermaid/)
With version 8.6.0 comes the release of directives for mermaid, a new system for modifying configurations, with the aim of establishing centralized, sane defaults and simple implementation.
`directives` allow for a diagram specific overriding of `config`, as it has been discussed in [Configurations](./Setup.md).
This allows site users to input modifications to `config` alongside diagram definitions, when creating diagrams on a private webpage that supports mermaid.
**A likely application for this is in the creation of diagrams/charts inside company/organizational webpages, that rely on mermaid for diagram and chart rendering.**
the `init` directive is the main method of configuration for Site and Current Levels.
The three levels of are Configuration, Global, Site and Current.
| Level of Configuration | Description |
| --- | --- |
| Global Configuration| Default Mermaid Configurations|
| Site Configuration| Configurations made by site owner|
| Current Configuration| Configurations made by Implementors|
# Limits to Modifying Configurations
secure Array
| Parameter | Description |Type | Required | Values|
| --- | --- | --- | --- | --- |
| secure | Array of parameters excluded from init directive| Array | Required | Any parameters|
The modifiable parts of the Configuration are limited by the secure array, which is an array of immutable parameters, this array can be expanded by site owners.
**Notes**: secure arrays work like nesting dolls, with the Global Configurations secure array being the default and immutable list of immutable parameters, or the smallest doll, to which site owners may add to, but implementors may not modify it.
# Secure Arrays
Site owners can add to the **secure** array using this command:
mermaidAPI.initialize( { startOnLoad: true, secure: ['parameter1', 'parameter2'] } );
default values for the `secure array` consists of: ['secure', 'securityLevel', 'startOnLoad', 'maxTextSize']. These default values are immutable.
Implementors can only modify configurations using directives, but cannot change the `secure` array.
# Modifying Configurations and directives:
The Two types of directives: are `init` or `initialize` and `wrap`.
**Notes**: All directives are enclosed in `%%{ }%%.`
Older versions of mermaid will not parse directives because `%%` will comment out the directive. This makes the update backward compatible.
# Init
`init`, or `initialize`: the init or initialize directive gives the user the ability to overwrite and change the values for configuration parameters, with respect to the secure array that is in effect.
| Parameter | Description |Type | Required | Values|
| --- | --- | --- | --- | --- |
| init | modifies configurations| Directive| Optional | Any parameters not included in the secure array|
**Notes:**
init would be an argument-directive: `%%{init: { **insert argument here**}}%%`
The json object that is passed as {**argument** } must be valid, quoted json or it will be ignored.
**for example**:
`%%{init: {"theme": default, "logLevel": 1 }}%%`
Configurations that are passed through init cannot change the parameters in secure arrays of higher levels. In the event of a conflict, mermaid will give priority to secure arrays and parse the request, without changing the values of the parameters in conflict.
When deployed within code, init is called before the graph/diagram description.
**for example**:
```
%%{init: {"theme": "default", "logLevel": 1 }}%%
graph LR
a-->b
b-->c
c-->d
d-->e
e-->f
f-->g
g-->
```
# Wrap
| Parameter | Description |Type | Required | Values|
| --- | --- | --- | --- | --- |
| wrap | a callable text-wrap function| Directive| Optional | %%{wrap}%%|
**Notes:**
Wrap is a function that is currently only deployable for sequence diagrams.
wrap respects manually added <br\> so if the user wants to break up their text, they have full control over those breaks by adding their own <br\> tags.
It is a non-argument directive and can be executed thusly:
`%%{wrap}%%` .
**an example of text wrapping in a sequence diagram**:
![Image showing wrapped text](./img/wrapped%20text.png)
# Resetting Configurations:
There are two more functions in the mermaidAPI that can be called by site owners: **reset** and **globalReset**.
**reset**: resets the configuration to whatever the last configuration was. This can be done to undo more recent changes to the last mermaidAPI.initialize({...}) configuration.
**globalReset** will reset both the current configuration AND the site configuration back to the global defaults.
**Notes**: both reset and globalReset are only available to site owners, as such implementors would have to edit their configs with init.
# Additional Utils to mermaid
**memoize**: simple caching for computationally expensive functions. It reduces the rendering time for computationally intensive diagrams by about 90%.
**assignWithDepth** - this is an improvement on previous functions with config.js and Object.assign. The purpose of this function is to provide a sane mechanism for merging objects, similar to object.assign, but with depth.
Example of **assignWithDepth**:
![Image showing assignWithDepth](./img/assignWithDepth.png)
Example of **object.Assign**:
![Image showing object.assign without depth](./img/object.assign%20without%20depth.png)
**calculateTextDimensions, calculateTextWidth,** and **calculateTextHeight** - for measuring text dimensions, width and height.
**Notes**:For more information on usage, parameters, and return info for these new functions take a look at the jsdocs for them in the utils package.
# New API Requests Introduced in Version 8.6.0
## setSiteConfig
| Function | Description | Type | Values |Parameters|Returns|
| --------- | ------------------- | ------- | ------------------ | ------------------ | ------------------ |
| setSiteConfig|Sets the siteConfig to desired values | Put Request | Any Values, except ones in secure array|conf|siteConfig|
**Notes:
Sets the siteConfig. The siteConfig is a protected configuration for repeat use. Calls to reset() will reset
the currentConfig to siteConfig. Calls to reset(configApi.defaultConfig) will reset siteConfig and currentConfig
to the defaultConfig
Note: currentConfig is set in this function
Default value: At default, will mirror Global Config**
## getSiteConfig
| Function | Description | Type | Values |
| --------- | ------------------- | ------- | ------------------ |
| setSiteConfig|Returns the current siteConfig base configuration | Get Request | Returns Any Values in siteConfig|
**Notes :
Returns any values in siteConfig.**
## setConfig
| Function | Description | Type | Values |Parameters|Returns|
| --------- | ------------------- | ------- | ------------------ |----------|-------|
| setSiteConfig|Sets the siteConfig to desired values | Put Request| Any Values, those in secure array|conf|currentConfig merged with the sanitized conf|
**Notes :
Sets the currentConfig. The parameter conf is sanitized based on the siteConfig.secure keys. Any
values found in conf with key found in siteConfig.secure will be replaced with the corresponding
siteConfig value.**
## getConfig
| Function | Description | Type | Return Values |
| --------- | ------------------- | ------- | ------------------ |
| getConfig |Obtains the currentConfig | Get Request | Any Values from currentConfig|
**Notes :
Returns any values in currentConfig.**
## sanitize
| Function | Description | Type | Values |
| --------- | ------------------- | ------- | ------------------ |
| sanitize |Sets the siteConfig to desired values. | Put Request(?) |None|
**Note: modifies options in-place
Ensures options parameter does not attempt to override siteConfig secure keys.**
## reset
| Function | Description | Type | Required | Values |Parameter|
| --------- | -------------------| ------- | -------- | ------------------ |---------|
| reset|Resets currentConfig to conf| Put Request | Required | None| conf|
## 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|
**Notes :
default: current siteConfig (optional, default `getSiteConfig()`)**
## For more information, read [Setup](https://mermaid-js.github.io/mermaid/#/Setup).

View File

@ -1,5 +1,7 @@
# Change Log
**Edit this Page** [![N|Solid](./img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/CHANGELOG.md)
## [Unreleased](https://github.com/knsv/mermaid/tree/HEAD)
[Full Changelog](https://github.com/knsv/mermaid/compare/8.1.0...HEAD)
@ -856,4 +858,4 @@
## [0.1.0](https://github.com/knsv/mermaid/tree/0.1.0) (2014-11-16)
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*

View File

@ -5,17 +5,41 @@
[![Join the chat at https://gitter.im/knsv/mermaid](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/knsv/mermaid?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
![banner](./img/header.png)
**Edit this Page** [![N|Solid](./img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/README.md)
Generation of diagrams and flowcharts from text in a similar manner as markdown.
Ever wanted to simplify documentation and avoid heavy tools like Visio when explaining your code?
This is why mermaid was born, a simple markdown-like script language for generating charts from text via javascript.
Check out the list of [Integrations and Usages of Mermaid](./integrations.md)
**Mermaid was nominated and won the JS Open Source Awards (2019) in the category "The most exciting use of technology"!!! Thanks to all involved, people committing pull requests, people answering questions and special thanks to Tyler Long who is helping me maintain the project.**
Mermaid is a tool that generates diagrams and charts, from markdown-inspired text definitions
This allows for simplified generation and updating of even the most complex diagrams and charts, while avoiding time-damanding and heavy tools like visio.
mermaid, is a simple markdown-inspired script language for generating charts from text-definitions, via javascript. As such, using it cuts the times it takes to create, modify and render diagrams.
Even non-programmers can create diagrams through the [mermaid live editor](https://github.com/mermaidjs/mermaid-live-editor).
For a more detailed introduction to mermaid, look to the [Beginner's Guide](https://mermaid-js.github.io/mermaid/#/n00b-overview) section.
You should also Check out the list of [Integrations and Usages of Mermaid](./integrations.md)
You can also watch some popular mermaid tutorials on the [mermaid Overview](./n00b-overview.md)
## [CDN](https://unpkg.com/mermaid/)
## [Documentation](https://mermaidjs.github.io)
## [Contribution](https://github.com/mermaid-js/mermaid/blob/develop/CONTRIBUTING.md)
# New in Version 8.6.0
## [New Mermaid Live-Editor Beta](https://mermaid-js.github.io/docs/mermaid-live-editor-beta/#/edit/eyJjb2RlIjoiJSV7aW5pdDoge1widGhlbWVcIjogXCJmb3Jlc3RcIiwgXCJsb2dMZXZlbFwiOiAxIH19JSVcbmdyYXBoIFREXG4gIEFbQ2hyaXN0bWFzXSAtLT58R2V0IG1vbmV5fCBCKEdvIHNob3BwaW5nKVxuICBCIC0tPiBDe0xldCBtZSB0aGlua31cbiAgQyAtLT58T25lfCBEW0xhcHRvcF1cbiAgQyAtLT58VHdvfCBFW2lQaG9uZV1cbiAgQyAtLT58VGhyZWV8IEZbZmE6ZmEtY2FyIENhcl1cblx0XHQiLCJtZXJtYWlkIjp7InRoZW1lIjoiZGFyayJ9fQ)
## [New Configuration Protocols in version 8.6.0](./8.6.0_docs.md)
## New diagrams in 8.5
With version 8.5 there are some bug fixes and enhancements, plus a new diagram type, entity relationship diagrams.
@ -24,16 +48,25 @@ With version 8.5 there are some bug fixes and enhancements, plus a new diagram t
## Special note regarding version 8.2
In version 8.2 a security improvement was introduced. A securityLevel configuration was introduced which sets the level of trust to be used on the parsed diagrams.
In version 8.2 a security improvement was introduced. A **securityLevel** configuration was introduced which sets the level of trust to be used on the parsed diagrams.
## securityLevel
| Parameter | Description | Type | Required | Values |
| ------------- | --------------------------------- | ------ | -------- | ------------- |
| securitylevel | Level of trust for parsed diagram | String | Required | Strict, Loose |
\*\*Notes:
- **strict**: (**default**) tags in text are encoded, click functionality is disabeled
- **loose**: tags in text are allowed, click functionality is enabled
- **true**: (default) tags in text are encoded, click functionality is disabled
- false: tags in text are allowed, click functionality is enabled
Closed issues:
⚠️ **Note** : This changes the default behaviour of mermaid so that after upgrade to 8.2, if the securityLevel is not configured, tags in flowcharts are encoded as tags and clicking is prohibited.
If your application is taking resposibility for the diagram source security you can set the securityLevel accordingly. By doing this clicks and tags are again allowed.
If your application is taking responsibility for the diagram source security you can set the securityLevel accordingly. By doing this clicks and tags are again allowed.
```javascript
mermaidAPI.initialize({
@ -43,9 +76,9 @@ mermaidAPI.initialize({
**🖖 Keep a steady pulse: mermaid needs more Collaborators [#866](https://github.com/knsv/mermaid/issues/866)**
## Diagrams
# Diagrams that mermaid can render:
### Flowchart
### [Flowchart](https://mermaid-js.github.io/mermaid/#/flowchart)
```
graph TD;
@ -57,7 +90,7 @@ graph TD;
![Flowchart](./img/flow.png)
### Sequence diagram
### [Sequence diagram](https://mermaid-js.github.io/mermaid/#/sequenceDiagram)
```
sequenceDiagram
@ -75,7 +108,7 @@ sequenceDiagram
![Sequence diagram](./img/sequence.png)
### Gantt diagram
### [Gantt diagram](https://mermaid-js.github.io/mermaid/#/gantt)
```
gantt
@ -92,7 +125,7 @@ Future task2 : des4, after des3, 5d
![Gantt diagram](./img/gantt.png)
### Class diagram - :exclamation: experimental
### [Class diagram - :exclamation: experimental](https://mermaid-js.github.io/mermaid/#/classDiagram)
```
classDiagram
@ -134,10 +167,9 @@ commit
merge newbranch
```
![Git graph](./img/git.png)
### Entity Relationship Diagram - :exclamation: experimental
### [Entity Relationship Diagram - :exclamation: experimental](https://mermaid-js.github.io/mermaid/#/entityRelationshipDiagram)
```
erDiagram
@ -149,6 +181,21 @@ erDiagram
![ER diagram](./img/simple-er.png)
### [User Journey Diagram](https://mermaid-js.github.io/mermaid/#/user-journey)
```markdown
journey
title My working day
section Go to work
Make tea: 5: Me
Go upstairs: 3: Me
Do work: 1: Me, Cat
section Go home
Go downstairs: 5: Me
Sit down: 5: Me
```
![Journey diagram](./img/user-journey.png)
## Installation
### CDN
@ -157,24 +204,43 @@ erDiagram
https://unpkg.com/mermaid@<version>/dist/
```
Replace `<version>` with expected version number.
To select a version:
Example: https://unpkg.com/mermaid@7.1.0/dist/
Replace `<version>` with the desired version number.
### Node.js
Alternatively, you can also adjust the version number in the page itself.
Latest Version: https://unpkg.com/browse/mermaid@8.6.0/
## Incorporating mermaid to a website
to support mermaid on your website, all you have to do is add Mermaids JavaScript package
```
yarn add mermaid
1.You will need to isntall node v10 or 12, which would have npm
2. download yarn using npm.
2. enter the following command:
yarn add mermaid
3. You can then add mermaid as a dev dependency using this command:
yarn add --dev mermaid
```
## Documentation
## To install mermaid without a bundler, one can use the script tag like so:
https://mermaidjs.github.io
<script src="https://unpkg.com/mermaid/"></script>
<script>mermaid.initialize({startOnLoad:true});</script>
## it can then be followed by the diagram definitions as could be found in the [examples in the documentation](https://mermaid-js.github.io/mermaid/#/n00b-gettingStarted).
## On your page mermaid will look for tags with class="mermaid". From these tags mermaid will try to read the chart definiton and replace it with an svg chart.
## Sibling projects
- [mermaid CLI](https://github.com/mermaidjs/mermaid.cli)
- [mermaid live editor](https://github.com/mermaidjs/mermaid-live-editor)
- [mermaid CLI](https://github.com/mermaidjs/mermaid.cli)
- [mermaid webpack demo](https://github.com/mermaidjs/mermaid-webpack-demo)
- [mermaid Parcel demo](https://github.com/mermaidjs/mermaid-parcel-demo)

933
docs/Setup.md Normal file
View File

@ -0,0 +1,933 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
## mermaidAPI
This is the api to be used when optionally handling the integration with the web page, instead of using the default integration provided by mermaid.js.
The core of this api is the [**render**][1] function which, given a graph
definition as text, renders the graph/diagram and returns an svg element for the graph.
It is is then up to the user of the API to make use of the svg, either insert it somewhere in the page or do something completely different.
In addition to the render function, a number of behavioral configuration options are available.
## Configuration
**Configuration methods in Mermaid version 8.6.0 have been updated, to learn more\[[click here][2]].**
## **What follows are config instructions for older versions**
These are the default options which can be overridden with the initialization call like so:
**Example 1:**
<pre>
mermaid.initialize({
flowchart:{
htmlLabels: false
}
});
</pre>
**Example 2:**
<pre>
&lt;script>
var config = {
startOnLoad:true,
flowchart:{
useMaxWidth:true,
htmlLabels:true,
curve:'cardinal',
},
securityLevel:'loose',
};
mermaid.initialize(config);
&lt;/script>
</pre>
A summary of all options and their defaults is found [here][3]. A description of each option follows below.
## theme
theme , the CSS style sheet
theme , the CSS style sheet
| Parameter | Description | Type | Required | Values |
| --------- | --------------- | ------ | -------- | ---------------------------------------------------- |
| Theme | Built in Themes | String | Optional | Values include, default, forest, dark, neutral, null |
**Notes:**To disable any pre-defined mermaid theme, use "null".
<pre>
"theme": "forest",
"themeCSS": ".node rect { fill: red; }"
</pre>
## fontFamily
| Parameter | Description | Type | Required | Values |
| ---------- | ------------------------------------------------------ | ------ | -------- | ----------------------------- |
| fontFamily | specifies the font to be used in the rendered diagrams | String | Required | Verdana, Arial, Trebuchet MS, |
\*\*notes: Default value is \\"trebuchet ms\\".
## logLevel
| Parameter | Description | Type | Required | Values |
| --------- | ----------------------------------------------------- | ------ | -------- | ------------- |
| logLevel | This option decides the amount of logging to be used. | String | Required | 1, 2, 3, 4, 5 |
**Notes:**
- debug: 1.
- info: 2.
- warn: 3.
- error: 4.
- fatal: 5(default).
## securityLevel
| Parameter | Description | Type | Required | Values |
| ------------- | --------------------------------- | ------ | -------- | ------------------------- |
| securitylevel | Level of trust for parsed diagram | String | Required | Strict, Loose, antiscript |
\*\*Notes:
- **strict**: (**default**) tags in text are encoded, click functionality is disabeled
- **loose**: tags in text are allowed, click functionality is enabled
- **antiscript**: html tags in text are allowed, (only script element is removed), click functionality is enabled
## startOnLoad
| Parameter | Description | Type | Required | Values |
| ----------- | --------------------------------------------- | ------- | -------- | ----------- |
| startOnLoad | Dictates whether mermaind starts on Page load | Boolean | Required | True, False |
**Notes:**
**Default value: true**
## arrowMarkerAbsolute
| Parameter | Description | Type | Required | Values |
| ------------------- | ---------------------------------------------------------------------------- | ------- | -------- | ----------- |
| arrowMarkerAbsolute | Controls whether or arrow markers in html code are absolute paths or anchors | Boolean | Required | True, False |
## Notes\*\*: This matters if you are using base tag settings.
**Default value: false**.
## secure
This option controls which currentConfig keys are considered _secure_ and can only be changed via
call to mermaidAPI.initialize. Calls to mermaidAPI.reinitialize cannot make changes to
the `secure` keys in the current currentConfig. This prevents malicious graph directives from
overriding a site's default security.
## flowchart
The object containing configurations specific for flowcharts
### diagramPadding
| Parameter | Description | Type | Required | Values |
| -------------- | ----------------------------------------------- | ------- | -------- | ------------------ |
| diagramPadding | amount of padding around the diagram as a whole | Integer | Required | Any Positive Value |
**Notes:**The amount of padding around the diagram as a whole so that embedded diagrams have margins, expressed in pixels
**Default value: 8**.
### htmlLabels
| Parameter | Description | Type | Required | Values |
| ---------- | -------------------------------------------------------------------------------------------- | ------- | -------- | ----------- |
| htmlLabels | Flag for setting whether or not a html tag should be used for rendering labels on the edges. | Boolean | Required | True, False |
**Notes: Default value: true**.
### nodeSpacing
| Parameter | Description | Type | Required | Values |
| ----------- | --------------------------------------------------- | ------- | -------- | -------------------- |
| nodeSpacing | Defines the spacing between nodes on the same level | Integer | Required | Any positive Numbers |
**Notes:
Pertains to horizontal spacing for TB (top to bottom) or BT (bottom to top) graphs, and the vertical spacing for LR as well as RL graphs.**
**Default value 50**.
### rankSpacing
| Parameter | Description | Type | Required | Values |
| ----------- | ----------------------------------------------------- | ------- | -------- | -------------------- |
| rankSpacing | Defines the spacing between nodes on different levels | Integer | Required | Any Positive Numbers |
**Notes: pertains to vertical spacing for TB (top to bottom) or BT (bottom to top), and the horizontal spacing for LR as well as RL graphs.
**Default value 50\*\*.
### curve
| Parameter | Description | Type | Required | Values |
| --------- | -------------------------------------------------- | ------ | -------- | ----------------------- |
| curve | Defines how mermaid renders curves for flowcharts. | String | Required | Basis, Linear, Cardinal |
**Notes:
Default Vaue: Linear**
## sequence
The object containing configurations specific for sequence diagrams
### activationWidth
widt of the activation rect
**Default value 10**.
### diagramMarginX
| Parameter | Description | Type | Required | Values |
| -------------- | ---------------------------------------------------- | ------- | -------- | ------------------- |
| diagramMarginX | margin to the right and left of the sequence diagram | Integer | Required | Any Positive Values |
**Notes:**
**Default value 50**.
### diagramMarginY
| Parameter | Description | Type | Required | Values |
| -------------- | ------------------------------------------------- | ------- | -------- | ------------------- |
| diagramMarginY | Margin to the over and under the sequence diagram | Integer | Required | Any Positive Values |
**Notes:**
**Default value 10**.
### actorMargin
| Parameter | Description | Type | Required | Values |
| ----------- | ---------------------- | ------- | -------- | ------------------ |
| actorMargin | Margin between actors. | Integer | Required | Any Positive Value |
**Notes:**
**Default value 50**.
### width
| Parameter | Description | Type | Required | Values |
| --------- | -------------------- | ------- | -------- | ------------------ |
| width | Width of actor boxes | Integer | Required | Any Positive Value |
**Notes:**
**Default value 150**.
### height
| Parameter | Description | Type | Required | Values |
| --------- | --------------------- | ------- | -------- | ------------------ |
| height | Height of actor boxes | Integer | Required | Any Positive Value |
**Notes:**
**Default value 65**..
### boxMargin
| Parameter | Description | Type | Required | Values |
| --------- | ------------------------ | ------- | -------- | ------------------ |
| boxMargin | Margin around loop boxes | Integer | Required | Any Positive Value |
**Notes:**
**Default value 10**.
### boxTextMargin
| Parameter | Description | Type | Required | Values |
| ------------- | -------------------------------------------- | ------- | -------- | ------------------ |
| boxTextMargin | margin around the text in loop/alt/opt boxes | Integer | Required | Any Positive Value |
**Notes:**
**Default value 5**.
### noteMargin
| Parameter | Description | Type | Required | Values |
| ---------- | -------------------- | ------- | -------- | ------------------ |
| noteMargin | margin around notes. | Integer | Required | Any Positive Value |
**Notes:**
**Default value 10**.
### messageMargin
| Parameter | Description | Type | Required | Values |
| ------------- | ----------------------- | ------- | -------- | ------------------ |
| messageMargin | Space between messages. | Integer | Required | Any Positive Value |
**Notes:**
Space between messages.
**Default value 35**.
### messageAlign
| Parameter | Description | Type | Required | Values |
| ------------ | --------------------------- | ------- | -------- | ------------------- |
| messageAlign | Multiline message alignment | Integer | Required | left, center, right |
**Notes:**center **default**
### mirrorActors
| Parameter | Description | Type | Required | Values |
| ------------ | ---------------------------- | ------- | -------- | ----------- |
| mirrorActors | mirror actors under diagram. | Boolean | Required | True, False |
**Notes:**
**Default value true**.
### bottomMarginAdj
| Parameter | Description | Type | Required | Values |
| --------------- | ------------------------------------------- | ------- | -------- | ------------------ |
| bottomMarginAdj | Prolongs the edge of the diagram downwards. | Integer | Required | Any Positive Value |
**Notes:**Depending on css styling this might need adjustment.
**Default value 1**.
### 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**.
### rightAngles
| Parameter | Description | Type | Required | Values |
| ----------- | ------------------------------------ | ------- | -------- | ----------- |
| rightAngles | display curve arrows as right angles | Boolean | Required | True, False |
**Notes:**
This will display arrows that start and begin at the same node as right angles, rather than a curve
**Default value false**.
### showSequenceNumbers
| Parameter | Description | Type | Required | Values |
| ------------------- | ------------------------------- | ------- | -------- | ----------- |
| showSequenceNumbers | This will show the node numbers | Boolean | Required | True, False |
**Notes:**
**Default value false**.
### actorFontSize
| Parameter | Description | Type | Required | Values |
| ------------- | -------------------------------------------------- | ------- | -------- | ------------------ |
| actorFontSize | This sets the font size of the actor's description | Integer | Require | Any Positive Value |
**Notes:**
**Default value 14**..
### actorFontFamily
| Parameter | Description | Type | Required | Values |
| --------------- | ---------------------------------------------------- | ---- | -------- | --------------------- |
| actorFontFamily | This sets the font family of the actor's description | 3 | 4 | Open-Sans, Sans-Serif |
**Notes:**
**Default value "Open-Sans", "sans-serif"**.
### actorFontWeight
This sets the font weight of the actor's description
\*\*Default value 400.
### noteFontSize
| Parameter | Description | Type | Required | Values |
| ------------ | ------------------------------------------------ | ------- | -------- | ------------------ |
| noteFontSize | This sets the font size of actor-attached notes. | Integer | Required | Any Positive Value |
**Notes:**
**Default value 14**..
### noteFontFamily
| Parameter | Description | Type | Required | Values |
| -------------- | -------------------------------------------------- | ------ | -------- | ---------------------------- |
| noteFontFamily | This sets the font family of actor-attached notes. | String | Required | trebuchet ms, verdana, arial |
**Notes:**
**Default value: trebuchet ms **.
### noteFontWeight
This sets the font weight of the note's description
\*\*Default value 400.
### noteAlign
| Parameter | Description | Type | Required | Values |
| --------- | ----------------------------------------------------- | ------ | -------- | ------------------- |
| noteAlign | This sets the text alignment of actor-attached notes. | string | required | left, center, right |
**Notes:**
**Default value center**.
### messageFontSize
| Parameter | Description | Type | Required | Values |
| --------------- | ------------------------------------------ | ------- | -------- | ------------------- |
| messageFontSize | This sets the font size of actor messages. | Integer | Required | Any Positive Number |
**Notes:**
**Default value 16**.
### messageFontFamily
| Parameter | Description | Type | Required | Values |
| ----------------- | -------------------------------------------- | ------ | -------- | ---------------------------- |
| messageFontFamily | This sets the font family of actor messages. | String | Required | trebuchet ms", verdana, aria |
**Notes:**
**Default value:"trebuchet ms**.
### messageFontWeight
This sets the font weight of the message's description
\*\*Default value 400.
### wrap
This sets the auto-wrap state for the diagram
\*\*Default value false.
### wrapPadding
This sets the auto-wrap padding for the diagram (sides only)
\*\*Default value 10.
### labelBoxWidth
This sets the width of the loop-box (loop, alt, opt, par)
\*\*Default value 50.
### labelBoxHeight
This sets the height of the loop-box (loop, alt, opt, par)
\*\*Default value 20.
## gantt
The object containing configurations specific for gantt diagrams\*
### titleTopMargin
### titleTopMargin
| Parameter | Description | Type | Required | Values |
| -------------- | ---------------------------------------------- | ------- | -------- | ------------------ |
| titleTopMargin | Margin top for the text over the gantt diagram | Integer | Required | Any Positive Value |
**Notes:**
**Default value 25**.
### barHeight
| Parameter | Description | Type | Required | Values |
| --------- | ----------------------------------- | ------- | -------- | ------------------ |
| barHeight | The height of the bars in the graph | Integer | Required | Any Positive Value |
**Notes:**
**Default value 20**.
### barGap
| Parameter | Description | Type | Required | Values |
| --------- | ----------------------------------------------------------------- | ------- | -------- | ------------------ |
| barGap | The margin between the different activities in the gantt diagram. | Integer | Optional | Any Positive Value |
**Notes:**
**Default value 4**.
### topPadding
| Parameter | Description | Type | Required | Values |
| ---------- | -------------------------------------------------------------------------- | ------- | -------- | ------------------ |
| topPadding | Margin between title and gantt diagram and between axis and gantt diagram. | Integer | Required | Any Positive Value |
**Notes:**
**Default value 50**.
### leftPadding
| Parameter | Description | Type | Required | Values |
| ----------- | ----------------------------------------------------------------------- | ------- | -------- | ------------------ |
| leftPadding | The space allocated for the section name to the left of the activities. | Integer | Required | Any Positive Value |
**Notes:**
**Default value 75**.
### gridLineStartPadding
| Parameter | Description | Type | Required | Values |
| -------------------- | --------------------------------------------- | ------- | -------- | ------------------ |
| gridLineStartPadding | Vertical starting position of the grid lines. | Integer | Required | Any Positive Value |
**Notes:**
**Default value 35**.
### fontSize
| Parameter | Description | Type | Required | Values |
| --------- | ----------- | ------- | -------- | ------------------ |
| fontSize | Font size | Integer | Required | Any Positive Value |
**Notes:**
**Default value 11**.
### fontFamily
| Parameter | Description | Type | Required | Values |
| ---------- | ----------- | ------ | -------- | ------------------------- |
| fontFamily | font Family | string | required | "Open-Sans", "sans-serif" |
**Notes:**
**Default value '"Open-Sans", "sans-serif"'**.
### numberSectionStyles
| Parameter | Description | Type | Required | Values |
| ------------------- | ---------------------------------------- | ------- | -------- | ------------------ |
| numberSectionStyles | The number of alternating section styles | Integer | 4 | Any Positive Value |
**Notes:**
**Default value 4**.
### axisFormat
| Parameter | Description | Type | Required | Values |
| ---------- | ---------------------------- | ---- | -------- | ---------------- |
| axisFormat | Datetime format of the axis. | 3 | Required | Date in yy-mm-dd |
**Notes:**
This might need adjustment to match your locale and preferences
**Default value '%Y-%m-%d'**.
## journey
The object containing configurations specific for journey diagrams
### diagramMarginX
| Parameter | Description | Type | Required | Values |
| -------------- | ---------------------------------------------------- | ------- | -------- | ------------------ |
| diagramMarginX | margin to the right and left of the sequence diagram | Integer | Required | Any Positive Value |
**Notes:**
**Default value 50**.
### diagramMarginY
| Parameter | Description | Type | Required | Values |
| -------------- | -------------------------------------------------- | ------- | -------- | ------------------ |
| diagramMarginY | margin to the over and under the sequence diagram. | Integer | Required | Any Positive Value |
**Notes:**
**Default value 10**..
### actorMargin
| Parameter | Description | Type | Required | Values |
| ----------- | ---------------------- | ------- | -------- | ------------------ |
| actorMargin | Margin between actors. | Integer | Required | Any Positive Value |
**Notes:**
**Default value 50**.
### width
| Parameter | Description | Type | Required | Values |
| --------- | -------------------- | ------- | -------- | ------------------ |
| width | Width of actor boxes | Integer | Required | Any Positive Value |
**Notes:**
**Default value 150**.
### height
| Parameter | Description | Type | Required | Values |
| --------- | --------------------- | ------- | -------- | ------------------ |
| height | Height of actor boxes | Integer | Required | Any Positive Value |
**Notes:**
**Default value 65**.
### boxMargin
| Parameter | Description | Type | Required | Values |
| --------- | ------------------------ | ------- | -------- | ------------------ |
| boxMargin | Margin around loop boxes | Integer | Required | Any Positive Value |
**Notes:**
**Default value 10**.
### boxTextMargin
| Parameter | Description | Type | Required | Values |
| ------------- | -------------------------------------------- | ------- | -------- | ------------------ |
| boxTextMargin | margin around the text in loop/alt/opt boxes | Integer | Required | Any Positive Value |
**Notes:**
### noteMargin
| Parameter | Description | Type | Required | Values |
| ---------- | -------------------- | ------- | -------- | ------------------ |
| noteMargin | margin around notes. | Integer | Required | Any Positive Value |
**Notes:**
**Default value 10**.
### messageMargin
| Parameter | Description | Type | Required | Values |
| ------------- | ----------------------- | ------- | -------- | ------------------ |
| messageMargin | Space between messages. | Integer | Required | Any Positive Value |
**Notes:**
Space between messages.
**Default value 35**.
### messageAlign
| Parameter | Description | Type | Required | Values |
| ------------ | --------------------------- | ---- | -------- | ------------------- |
| messageAlign | Multiline message alignment | 3 | 4 | left, center, right |
**Notes:**default:center\*\*
### bottomMarginAdj
| Parameter | Description | Type | Required | Values |
| --------------- | ------------------------------------------- | ------- | -------- | ------------------ |
| bottomMarginAdj | Prolongs the edge of the diagram downwards. | Integer | 4 | Any Positive Value |
**Notes:**Depending on css styling this might need adjustment.
**Default value 1**.
### useMaxWidth
| Parameter | Description | Type | Required | Values |
| ----------- | ----------- | ------- | -------- | ----------- |
| useMaxWidth | See notes | Boolean | 4 | True, False |
**Notes:**when this flag is set the height and width is set to 100% and is then scaling with the
available space if not the absolute space required is used.
**Default value true**.
### rightAngles
| Parameter | Description | Type | Required | Values |
| ----------- | ---------------------------------- | ---- | -------- | ----------- |
| rightAngles | Curved Arrows become Right Angles, | 3 | 4 | True, False |
**Notes:**This will display arrows that start and begin at the same node as right angles, rather than a curves
**Default value false**.
## er
The object containing configurations specific for entity relationship diagrams
### diagramPadding
| Parameter | Description | Type | Required | Values |
| -------------- | ----------------------------------------------- | ------- | -------- | ------------------ |
| diagramPadding | amount of padding around the diagram as a whole | Integer | Required | Any Positive Value |
**Notes:**The amount of padding around the diagram as a whole so that embedded diagrams have margins, expressed in pixels
**Default value: 20**.
### layoutDirection
| Parameter | Description | Type | Required | Values |
| --------------- | ---------------------------------------- | ------ | -------- | -------------------- |
| layoutDirection | Directional bias for layout of entities. | String | Required | "TB", "BT","LR","RL" |
**Notes:**
'TB' for Top-Bottom, 'BT'for Bottom-Top, 'LR' for Left-Right, or 'RL' for Right to Left.
T = top, B = bottom, L = left, and R = right.
**Default value: TB **.
### minEntityWidth
| Parameter | Description | Type | Required | Values |
| -------------- | ----------------------------------- | ------- | -------- | ------------------ |
| minEntityWidth | The mimimum width of an entity box, | Integer | Required | Any Positive Value |
**Notes:**expressed in pixels
**Default value: 100**.
### minEntityHeight
| Parameter | Description | Type | Required | Values |
| --------------- | ------------------------------------ | ------- | -------- | ------------------ |
| minEntityHeight | The minimum height of an entity box, | Integer | 4 | Any Positive Value |
**Notes:**expressed in pixels
**Default value: 75 **
### entityPadding
| Parameter | Description | Type | Required | Values |
| ------------- | ------------------------------------------------------------ | ------- | -------- | ------------------ |
| entityPadding | minimum internal padding betweentext 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, expressed in pixels.
**Default value: 15 **
### stroke
| Parameter | Description | Type | Required | Values |
| --------- | ----------------------------------- | ------ | -------- | -------------------- |
| stroke | Stroke color of box edges and lines | String | 4 | Any recognized color |
**Default value: gray **
### fill
| Parameter | Description | Type | Required | Values |
| --------- | -------------------------- | ------ | -------- | -------------------- |
| fill | Fill color of entity boxes | String | 4 | Any recognized color |
**Notes:**
**Default value:'honeydew'**
### fontSize
| Parameter | Description | Type | Required | Values |
| --------- | ------------------- | ------- | -------- | ------------------ |
| fontSize | Font Size in pixels | Integer | | Any Positive Value |
**Notes:**Font size (expressed as an integer representing a number of pixels)
**Default value: 12 **
### useMaxWidth
| Parameter | Description | Type | Required | Values |
| ----------- | ----------- | ------- | -------- | ----------- |
| useMaxWidth | See Notes | Boolean | Required | true, false |
**Notes:**
When this flag is set to true, the diagram width is locked to 100% and
scaled based on available space. If set to false, the diagram reserves its
absolute width.
**Default value: true**.
## render
Function that renders an svg with a graph from a chart definition. Usage example below.
```js
mermaidAPI.initialize({
startOnLoad:true
});
$(function(){
const graphDefinition = 'graph TB\na-->b';
const cb = function(svgGraph){
console.log(svgGraph);
};
mermaidAPI.render('id1',graphDefinition,cb);
});
```
### Parameters
- `id` the id of the element to be rendered
- `_txt` the graph definition
- `cb` callback which is called after rendering is finished with the svg code as inparam.
- `container` selector to element in which a div with the graph temporarily will be inserted. In one is
provided a hidden div will be inserted in the body of the page instead. The element will be removed when rendering is
completed.
##
## mermaidAPI configuration defaults
<pre>
&lt;script>
var config = {
theme:'default',
logLevel:'fatal',
securityLevel:'strict',
startOnLoad:true,
arrowMarkerAbsolute:false,
er:{
diagramPadding:20,
layoutDirection:'TB',
minEntityWidth:100,
minEntityHeight:75,
entityPadding:15,
stroke:'gray',
fill:'honeydew',
fontSize:12,
useMaxWidth:true,
},
flowchart:{
diagramPadding:8,
htmlLabels:true,
curve:'linear',
},
sequence:{
diagramMarginX:50,
diagramMarginY:10,
actorMargin:50,
width:150,
height:65,
boxMargin:10,
boxTextMargin:5,
noteMargin:10,
messageMargin:35,
messageAlign:'center',
mirrorActors:true,
bottomMarginAdj:1,
useMaxWidth:true,
rightAngles:false,
showSequenceNumbers:false,
},
gantt:{
titleTopMargin:25,
barHeight:20,
barGap:4,
topPadding:50,
leftPadding:75,
gridLineStartPadding:35,
fontSize:11,
fontFamily:'"Open-Sans", "sans-serif"',
numberSectionStyles:4,
axisFormat:'%Y-%m-%d',
}
};
mermaid.initialize(config);
&lt;/script>
</pre>
## setSiteConfig
## setSiteConfig
| Function | Description | Type | Values |
| ------------- | ------------------------------------- | ----------- | --------------------------------------- |
| setSiteConfig | Sets the siteConfig to desired values | Put Request | Any Values, except ones in secure array |
**Notes:**
Sets the siteConfig. The siteConfig is a protected configuration for repeat use. Calls to reset() will reset
the currentConfig to siteConfig. Calls to reset(configApi.defaultConfig) will reset siteConfig and currentConfig
to the defaultConfig
Note: currentConfig is set in this function
\*Default value: At default, will mirror Global Config\*\*
### Parameters
- `conf` the base currentConfig to use as siteConfig
Returns **any** the siteConfig
## getSiteConfig
## getSiteConfig
| Function | Description | Type | Values |
| ------------- | ------------------------------------------------- | ----------- | --------------------------------- |
| setSiteConfig | Returns the current siteConfig base configuration | Get Request | Returns Any Values in siteConfig |
**Notes**:
Returns **any** values in siteConfig.
Returns **any**
## setConfig
## setConfig
| Function | Description | Type | Values |
| ------------- | ------------------------------------- | ----------- | --------------------------------------- |
| setSiteConfig | Sets the siteConfig to desired values | Put Request | Any Values, except ones in secure array |
**Notes**:
Sets the currentConfig. The parameter conf is sanitized based on the siteConfig.secure keys. Any
values found in conf with key found in siteConfig.secure will be replaced with the corresponding
siteConfig value.
### Parameters
- `conf` the potential currentConfig
Returns **any** the currentConfig merged with the sanitized conf
## getConfig
## getConfig
| Function | Description | Type | Return Values |
| --------- | ------------------------- | ----------- | ----------------------------- |
| getConfig | Obtains the currentConfig | Get Request | Any Values from currentConfig |
**Notes**:
Returns **any** the currentConfig
Returns **any** the currentConfig
## sanitize
## sanitize
| Function | Description | Type | Values |
| -------- | -------------------------------------- | ----------- | ------ |
| sanitize | Sets the siteConfig to desired values. | Put Request | None |
Ensures options parameter does not attempt to override siteConfig secure keys
Note: modifies options in-place
### Parameters
- `options` the potential setConfig parameter
## reset
## reset
| Function | Description | Type | Required | Values |
| -------- | ---------------------------- | ----------- | -------- | ------ |
| reset | Resets currentConfig to conf | Put Request | Required | None |
| 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 |
\*Notes :
(default: current siteConfig ) (optional, default `getSiteConfig()`)
### Parameters
- `conf` the base currentConfig to reset to (default: current siteConfig ) (optional, default `getSiteConfig()`)
[1]: Setup.md?id=render
[2]: 8.6.0_docs.md
[3]: #mermaidapi-configuration-defaults

View File

@ -3,6 +3,7 @@
- [mermaid](README.md)
- [FAQ](faq.md)
- [Usage](usage.md)
- [Integrations](integrations.md)
- [Examples](examples.md)
- [mermaid CLI](mermaidCLI.md)
@ -16,15 +17,17 @@
- [User Journey](user-journey.md)
- [Gantt](gantt.md)
- [Pie Chart](pie.md)
- [Directives](directives.md)
- Guide
- [Development](development.md)
- [mermaidAPI](mermaidAPI.md)
- [Configurations](Setup.md)
- [Changelog](CHANGELOG.md)
- I'm a n00b
- Beginner's Guide
- [overview](n00b-overview.md)
- [Getting started - easier](n00b-gettingStarted.md)
- [Theming](theming.md)
- [Diagram syntax intro](n00b-syntaxReference.md)
- [Advanced usage](n00b-advanced.md)

View File

@ -1,5 +1,5 @@
# Breaking changes
**Edit this Page** [![N|Solid](./img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/breakingChanges.md)
### Breaking changes from history version to latest version:
## #1

View File

@ -1,4 +1,5 @@
# Class diagrams
**Edit this Page** [![N|Solid](./img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/classDiagram.md)
> "In software engineering, a class diagram in the Unified Modeling Language (UML) is a type of static structure diagram that describes the structure of a system by showing the system's classes, their attributes, operations (or methods), and the relationships among objects."
Wikipedia

View File

@ -1,6 +1,6 @@
# Development
**Edit this Page** [![N|Solid](./img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/development.md)
## Updating the documentation
Please continue writing documentation at [mermaid-js/mermaid/docs](https://github.com/mermaid-js/mermaid/tree/develop/docs).

80
docs/directives.md Normal file
View File

@ -0,0 +1,80 @@
## Directives
**Edit this Page** [![N|Solid](./img/GitHub-Mark-32px.png)](./directives.md)
## Directives were added in [Version 8.6.0](/8.6.0_docs.md). Please Read it for more information.
## Directives
With this version, directives are supported. Directives are divided in two sets, by priority. the first set, containing 'init' or 'initialize' directives take priority. While the other set, containing all other kinds of directives are considered only after 'init' and the graph-type declared.
#### Init
| Parameter | Description |Type | Required | Values|
| --- | --- | --- | --- | --- |
| init | modifies configurations| Directive| Optional | Any parameters not included in the secure array|
**Notes:**
init would be an argument-directive: %%{init: { **insert argument here**}}%%
The json object that is passed as {**argument** } must be valid, quoted json or it will be ignored.
The init/initialize directive is parsed early in the flow, enough to be able to re-initialize mermaid with a new configuration object. Example:
```
%%{init: { 'logLevel': 'debug', 'theme': 'dark' } }%%
graph >
A-->B
```
will set the `logLevel` to `debug` and the `theme` to `dark` for a flowchart diagram.
Note: 'init' or 'initialize' are both acceptable as init directives. Also note that init directives are coalesced. This means:
```
%%{init: { 'logLevel': 'debug', 'theme': 'forest' } }%%
%%{initialize: { 'logLevel': 'fatal', "theme":'dark', 'startOnLoad': true } }%%
...
```
will result an init object looking like this:
```
{
logLevel: 'fatal',
theme: 'dark',
startOnLoad: true
}
```
to be sent to `mermaid.initialize(...)`
#### Other directives
In this category are any directives that follow the graph type declaration. Essentially, these directives will not be processed early in the flow like the init directive. Each individual graph type will handle these directives. As an example:
```
%%{init: { 'logLevel': 'debug', 'theme': 'dark' } }%%
sequenceDiagram
%%{config: { 'fontFamily': 'Menlo', 'fontSize': 18, 'fontWeight': 400} }%%
Alice->>Bob: Hi Bob
Bob->>Alice: Hi Alice
```
## Chronology
This will set the `logLevel` to `debug` and `theme` to `dark` for a sequence diagram. Then, during processing, the config for the sequence diagram is set by the `config` directive. This directive is handled in the `sequenceDb.js`. In this example, the fontFamily, fontSize, and fontWeight are all set for this sequence diagram.
#### Backwards Compatibility
Init directives and any other non-multiline directives should be backwards compatible, because they will be treated as comments in prior versions of mermaid-js.
Multiline directives, however, will pose an issue and will render an error. This is unavoidable.
### Wrapping
The `%%{wrap}%%` directive and the inline `wrap:` text hint have also been added for sequence diagrams. This has been explained in my previous comments and has not materially changed.
# Wrap
| Parameter | Description |Type | Required | Values|
| --- | --- | --- | --- | --- |
| wrap | a callable text-wrap function| Directive| Optional | %%{wrap}%%|

View File

@ -5,17 +5,19 @@
Note that practitioners of ER modelling almost always refer to *entity types* simply as *entities*. For example the CUSTOMER entity type would be referred to simply as the CUSTOMER entity. This is so common it would be inadvisable to do anything else, but technically an entity is an abstract *instance* of an entity type, and this is what an ER diagram shows - abstract instances, and the relationships between them. This is why entities are always named using singular nouns.
Mermaid can render ER diagrams
```
erDiagram
CUSTOMER ||--o{ ORDER : places
ORDER ||--|{ LINE-ITEM : contains
CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
```
```mermaid
erDiagram
CUSTOMER ||--o{ ORDER : places
ORDER ||--|{ LINE-ITEM : contains
CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
```
```mermaid
erDiagram
CUSTOMER ||--o{ ORDER : places
ORDER ||--|{ LINE-ITEM : contains
CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
```
Entity names are often capitalised, although there is no accepted standard on this, and it is not required in Mermaid.
@ -31,9 +33,11 @@ ER diagrams are a new feature in Mermaid and are **experimental**. There are li
### Entities and Relationships
Mermaid syntax for ER diagrams is compatible with PlantUML, with an extension to label the relationship. Each statement consists of the following parts, all of which are mandatory:
```
```mermaid
<first-entity> <relationship> <second-entity> : <relationship-label>
```
Where:
- `first-entity` is the name of an entity. Names must begin with an alphabetic character and may also contain digits and hyphens
@ -43,7 +47,7 @@ Where:
For example:
```
```mermaid
PROPERTY ||--|{ ROOM : contains
```
@ -51,9 +55,9 @@ This statement can be read as *a property contains one or more rooms, and a room
### Relationship Syntax
The `relationship` part of each statement can be broken down into three sub-components:
The `relationship` part of each statement can be broken down into three sub-components:
- the cardinality of the first entity with respect to the second,
- the cardinality of the first entity with respect to the second,
- whether the relationship confers identity on a 'child' entity
- the cardinality of the second entity with respect to the first
@ -68,13 +72,37 @@ Cardinality is a property that describes how many elements of another entity can
### Identification
Relationships may be classified as either *identifying* or *non-identifying* and these are rendered with either solid or dashed lines respectively. This is relevant when one of the entities in question can not have independent existence without the other. For example a firm that insures people to drive cars might need to store data on `NAMED-DRIVER`s. In modelling this we might start out by observing that a `CAR` can be driven by many `PERSON` instances, and a `PERSON` can drive many `CAR`s - both entities can exist without the other, so this is a non-identifying relationship that we might specify in Mermaid as: `PERSON }|..|{ CAR : "driver"`. Note the two dots in the middle of the relationship that will result in a dashed line being drawn between the two entities. But when this many-to-many relationship is resolved into two one-to-many relationships, we observe that a `NAMED-DRIVER` cannot exist without both a `PERSON` and a `CAR` - the relationships become identifying and would be specified using hyphens, which translate to a solid line:
Relationships may be classified as either *identifying* or *non-identifying* and these are rendered with either solid or dashed lines respectively. This is relevant when one of the entities in question can not have independent existence without the other. For example a firm that insures people to drive cars might need to store data on `NAMED-DRIVER`s. In modelling this we might start out by observing that a `CAR` can be driven by many `PERSON` instances, and a `PERSON` can drive many `CAR`s - both entities can exist without the other, so this is a non-identifying relationship that we might specify in Mermaid as: `PERSON }|..|{ CAR : "driver"`. Note the two dots in the middle of the relationship that will result in a dashed line being drawn between the two entities. But when this many-to-many relationship is resolved into two one-to-many relationships, we observe that a `NAMED-DRIVER` cannot exist without both a `PERSON` and a `CAR` - the relationships become identifying and would be specified using hyphens, which translate to a solid line:
```
```mermaid
CAR ||--o{ NAMED-DRIVER : allows
PERSON ||--o{ NAMED-DRIVER : is
```
### Other Things
- If you want the relationship label to be more than one word, you must use double quotes around the phrase
- If you don't want a label at all on a relationship, you must use an empty double-quoted string
## Styling
### Config options
For simple color customization:
| Name | Used as |
| :------- | :------------------------------------------------------ |
| `fill` | Background color of an entity |
| `stroke` | Border color of an entity, line color of a relationship |
### Classes used
The following CSS class selectors are available for richer styling:
| Selector | Description |
| :------------------------- | :---------------------------------------------------- |
| `.er.entityBox` | The box representing an entity |
| `.er.entityLabel` | The label for an entity |
| `.er.relationshipLabel` | The label for a relationship |
| `.er.relationshipLabelBox` | The box surrounding a relationship label |
| `.er.relationshipLine` | The line representing a relationship between entities |

View File

@ -1,3 +1,13 @@
# Examples
**Edit this Page** [![N|Solid](./img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/examples.md)
This page contains a collection of examples of diagrams and charts that can be created through mermaid and its myriad applications.
## If you wish to learn how to support mermaid on your webpage, read the [Beginner's Guide](https://mermaid-js.github.io/mermaid/#/n00b-gettingStarted).
## If you wish to learn about mermaid's syntax, Read the [Diagram Syntax](https://mermaid-js.github.io/mermaid/#/n00b-syntaxReference) section.
## Basic Pie Chart
```

View File

@ -1,3 +1,7 @@
Frequently Asked Questions:
**Edit this Page** [![N|Solid](./img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/faq.md)
1. [How to add title to flowchart?](https://github.com/knsv/mermaid/issues/556#issuecomment-363182217)
1. [How to specify custom CSS file?](https://github.com/mermaidjs/mermaid.cli/pull/24#issuecomment-373402785)
1. [How to fix tooltip misplacement issue?](https://github.com/knsv/mermaid/issues/542#issuecomment-3343564621)
@ -5,4 +9,5 @@
1. [How to bind an event?](https://github.com/knsv/mermaid/issues/372)
1. [How to add newline in the text?](https://github.com/knsv/mermaid/issues/384#issuecomment-281339381)
1. [How to have special characters in link text?](https://github.com/knsv/mermaid/issues/407#issuecomment-329944735)
1. [How to change flowchart curve style?](https://github.com/knsv/mermaid/issues/580#issuecomment-373929046)
1. [How to change Flowchart curve style?](https://github.com/knsv/mermaid/issues/580#issuecomment-373929046)
1. [How to create a Flowchart end-Node that says "End"](https://github.com/mermaid-js/mermaid/issues/1444#issuecomment-639528897)

View File

@ -1,10 +1,11 @@
# Flowcharts - Basic Syntax
**Edit this Page** [![N|Solid](./img/GitHub-Mark-32px.png)](./flowchart.md)
## Graph
This statement declares a new graph and the direction of the graph layout.
This statement declares the direction of the Flowchart.
This declares a graph oriented from top to bottom (`TD` or `TB`).
This declares the graph is oriented from top to bottom (`TD` or `TB`).
```
graph TD
@ -15,7 +16,7 @@ graph TD
Start --> Stop
```
This declares a graph oriented from left to right (`LR`).
This declares the graph is oriented from left to right (`LR`).
```
graph LR
@ -26,18 +27,26 @@ graph LR
Start --> Stop
```
Possible directions are:
## Flowchart Orientation
* TB - top bottom
* BT - bottom top
* RL - right left
* LR - left right
Possible FlowChart orientations are:
* TD - same as TB
* TB - top to bottom
* TD - top-down/ same as top to bottom
* BT - bottom to top
* RL - right to left
* LR - left to right
## flowchart
This renders a flowchart in the same way as a graph but with a new rendering method opening up for long requested features such as: more arrow types, multi directional arrows, and linking to and from subgraphs. Apart from the graph type, flowchart/graph, the syntax is the same. This is currently experimental but when the beta period is over both the graph and flowchart keywords will render in the new way. This means it is ok to start beta testing flowcharts.
## Flowcharts
This renders a flowchart that allows for features such as: more arrow types, multi directional arrows, and linking to and from subgraphs.
Apart from the graph type, the syntax is the same. This is currently experimental but when the beta period is over, both the graph and flowchart keywords will render in the new way. This means it is ok to start beta testing flowcharts.
## An important note on Flowchart nodes, do not type the word "end" as a Flowchart node. Capitalize all or any one the letters to keep the flowchart from breaking, i.e, "End" or "END". Or you can apply this [workaround](https://github.com/mermaid-js/mermaid/issues/1444#issuecomment-639528897).
## Nodes & shapes
@ -52,7 +61,7 @@ graph LR
graph LR
id
```
Note that the id is what is displayed in the box.
# Note that the id is what is displayed in the box.
### A node with text
@ -69,6 +78,7 @@ graph LR
id1[This is the text in the box]
```
## Node Shapes
### A node with round edges

View File

@ -1,17 +1,19 @@
# Gantt diagrams
**Edit this Page** [![N|Solid](./img/GitHub-Mark-32px.png)](./gantt.md)
> A Gantt chart is a type of bar chart, first developed by Karol Adamiecki in 1896, and independently by Henry Gantt in the 1910s, that illustrates a project schedule and the amount of time it would take for any one project to finish. Gantt charts illustrate number of days between the start and finish dates of the terminal elements and summary elements of a project.
## A note to users
Gannt Charts will record each scheduled task as one continuous bar that extends from the left to the right. The x axis represents time and the y records the different tasks and the order in which they are to be completed.
Gantt Charts will record each scheduled task as one continuous bar that extends from the left to the right. The x axis represents time and the y records the different tasks and the order in which they are to be completed.
It is important to remember that when a date, day or collection of dates specific to a task are "excluded", the Gannt Chart will accomodate those changes by extending an equal number of day, towards the right, not by creating a gap inside the task.
As shown here ![](https://github.com/NeilCuzon/mermaid/blob/develop/docs/img/Gantt-excluded-days-within.png)
It is important to remember that when a date, day, or collection of dates specific to a task are "excluded", the Gantt Chart will accomodate those changes by extending an equal number of day, towards the right, not by creating a gap inside the task.
As shown here ![](https://raw.githubusercontent.com/NeilCuzon/mermaid/develop/docs/img/Gantt-excluded-days-within.png)
However, if the excluded date/s is between two tasks that are set to start consecutively, the excluded dates will be skipped graphically and left blank, and the following task will begin after the end of the excluded date/s.
As shown here ![](https://github.com/NeilCuzon/mermaid/blob/develop/docs/img/Gantt-long-weekend-look.png)
However, if the excluded dates are between two tasks that are set to start consecutively, the excluded dates will be skipped graphically and left blank, and the following task will begin after the end of the excluded dates.
As shown here ![](https://raw.githubusercontent.com/NeilCuzon/mermaid/develop/docs/img/Gantt-long-weekend-look.png)
A Gantt chart is useful for tracking the amount of time it would take before a project is finished, but it can also be used to graphically represent "non-working days, with a few tweaks.
A Gantt chart is useful for tracking the amount of time it would take before a project is finished, but it can also be used to graphically represent "non-working days", with a few tweaks.
Mermaid can render Gantt diagrams as SVG, PNG or a MarkDown link that can be pasted into docs.
@ -117,12 +119,14 @@ It is possible to set multiple depenendenies separated by space:
### Title
Tbd
The `title` is an *optional* string to be displayed at the top of the Gantt chart to describe the chart as a whole.
## Sections statements
### Section statements
Tbd
You can divide the chart into various sections, for example to separate different parts of a project like development and documentation.
To do so, start a line with the `section` keyword and give it a name. (Note that unlike with the [title for the entire chart](#title), this name is *required*.
## Setting dates
@ -293,6 +297,19 @@ noteText | Styles for the text on in the note boxes.
}
```
## Today marker
You can style or hide the marker for the current date. To style it, add a value for the `todayMarker` key.
```
todayMarker stroke-width:5px,stroke:#0f0,opacity:0.5
```
To hide the marker, set `todayMarker` to `off`.
```
todayMarker off
```
## Configuration

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
docs/img/user-journey.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
docs/img/without wrap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

BIN
docs/img/wrapped text.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

View File

@ -6,9 +6,10 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="description" content="Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css">
<script src="//cdn.jsdelivr.net/npm/mermaid@8.5.2/dist/mermaid.min.js"></script>
<!-- <script src="http://localhost:9000/mermaid.js"></script> -->
<!-- <link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css"> -->
<link rel="stylesheet" href="theme.css">
<!-- <script src="//cdn.jsdelivr.net/npm/mermaid@8.6.4/dist/mermaid.min.js"></script> -->
<script src="http://localhost:9000/mermaid.js"></script>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
@ -54,7 +55,11 @@
}
var num = 0;
mermaid.initialize({ logLevel:0, startOnLoad: false, themeCSS:'.label { font-family: Source Sans Pro,Helvetica Neue,Arial,sans-serif; }' });
const isDarkMode = window.matchMedia("(prefers-color-scheme: dark)").matches
const conf = { logLevel:4, startOnLoad: false, themeCSS:'.label { font-family: Source Sans Pro,Helvetica Neue,Arial,sans-serif; }' };
if(isDarkMode && false) conf.theme = 'dark';
mermaid.initialize(conf);
</script>
<script>

View File

@ -1,4 +1,5 @@
# Integrations
**Edit this Page** [![N|Solid](./img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/n00b-gettingStarted.md)
The following is a list of different integrations and plugins where mermaid is being used

View File

@ -1,493 +0,0 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
## mermaidAPI
This is the api to be used when optionally handling the integration with the web page, instead of using the default integration provided by mermaid.js.
The core of this api is the [**render**][1] function which, given a graph
definition as text, renders the graph/diagram and returns an svg element for the graph.
It is is then up to the user of the API to make use of the svg, either insert it somewhere in the page or do something completely different.
In addition to the render function, a number of behavioral configuration options are available.
## Configuration
These are the default options which can be overridden with the initialization call like so:
**Example 1:**
<pre>
mermaid.initialize({
flowchart:{
htmlLabels: false
}
});
</pre>
**Example 2:**
<pre>
&lt;script>
var config = {
startOnLoad:true,
flowchart:{
useMaxWidth:true,
htmlLabels:true,
curve:'cardinal',
},
securityLevel:'loose',
};
mermaid.initialize(config);
&lt;/script>
</pre>
A summary of all options and their defaults is found [here][2]. A description of each option follows below.
## theme
theme , the CSS style sheet
**theme** - Choose one of the built-in themes:
- default
- forest
- dark
- neutral.
To disable any pre-defined mermaid theme, use "null".
**themeCSS** - Use your own CSS. This overrides **theme**.
<pre>
"theme": "forest",
"themeCSS": ".node rect { fill: red; }"
</pre>
## fontFamily
**fontFamily** The font to be used for the rendered diagrams. Default value is \\"trebuchet ms\\", verdana, arial;
## logLevel
This option decides the amount of logging to be used.
- debug: 1
- info: 2
- warn: 3
- error: 4
- fatal: (**default**) 5
## securityLevel
Sets the level of trust to be used on the parsed diagrams.
- **strict**: (**default**) tags in text are encoded, click functionality is disabeled
- **loose**: tags in text are allowed, click functionality is enabled
## startOnLoad
This options controls whether or mermaid starts when the page loads
**Default value true**.
## arrowMarkerAbsolute
This options controls whether or arrow markers in html code will be absolute paths or
an anchor, #. This matters if you are using base tag settings.
**Default value false**.
## flowchart
The object containing configurations specific for flowcharts
### htmlLabels
Flag for setting whether or not a html tag should be used for rendering labels
on the edges.
**Default value true**.
### nodeSpacing
Defines the spacing between nodes on the same level (meaning horizontal spacing for
TB or BT graphs, and the vertical spacing for LR as well as RL graphs).
**Default value 50**.
### rankSpacing
Defines the spacing between nodes on different levels (meaning vertical spacing for
TB or BT graphs, and the horizontal spacing for LR as well as RL graphs).
**Default value 50**.
### curve
How mermaid renders curves for flowcharts. Possible values are
- basis
- linear **default**
- cardinal
## sequence
The object containing configurations specific for sequence diagrams
### diagramMarginX
margin to the right and left of the sequence diagram.
**Default value 50**.
### diagramMarginY
margin to the over and under the sequence diagram.
**Default value 10**.
### actorMargin
Margin between actors.
**Default value 50**.
### width
Width of actor boxes
**Default value 150**.
### height
Height of actor boxes
**Default value 65**.
### boxMargin
Margin around loop boxes
**Default value 10**.
### boxTextMargin
margin around the text in loop/alt/opt boxes
**Default value 5**.
### noteMargin
margin around notes.
**Default value 10**.
### messageMargin
Space between messages.
**Default value 35**.
### messageAlign
Multiline message alignment. Possible values are:
- left
- center **default**
- right
### mirrorActors
mirror actors under diagram.
**Default value true**.
### bottomMarginAdj
Depending on css styling this might need adjustment.
Prolongs the edge of the diagram downwards.
**Default value 1**.
### useMaxWidth
when this flag is set the height and width is set to 100% and is then scaling with the
available space if not the absolute space required is used.
**Default value true**.
### rightAngles
This will display arrows that start and begin at the same node as right angles, rather than a curve
**Default value false**.
### showSequenceNumbers
This will show the node numbers
**Default value false**.
### actorFontSize
This sets the font size of the actor's description
**Default value 14**.
### actorFontFamily
This sets the font family of the actor's description
**Default value "Open-Sans", "sans-serif"**.
### noteFontSize
This sets the font size of actor-attached notes.
**Default value 14**.
### noteFontFamily
This sets the font family of actor-attached notes.
**Default value "trebuchet ms", verdana, arial**.
### noteAlign
This sets the text alignment of actor-attached notes.
**Default value center**.
### messageFontSize
This sets the font size of actor messages.
**Default value 16**.
### messageFontFamily
This sets the font family of actor messages.
**Default value "trebuchet ms", verdana, arial**.
## gantt
The object containing configurations specific for gantt diagrams\*
### titleTopMargin
Margin top for the text over the gantt diagram
**Default value 25**.
### barHeight
The height of the bars in the graph
**Default value 20**.
### barGap
The margin between the different activities in the gantt diagram.
**Default value 4**.
### topPadding
Margin between title and gantt diagram and between axis and gantt diagram.
**Default value 50**.
### leftPadding
The space allocated for the section name to the left of the activities.
**Default value 75**.
### gridLineStartPadding
Vertical starting position of the grid lines.
**Default value 35**.
### fontSize
Font size ...
**Default value 11**.
### fontFamily
font family ...
**Default value '"Open-Sans", "sans-serif"'**.
### numberSectionStyles
The number of alternating section styles.
**Default value 4**.
### axisFormat
Datetime format of the axis. This might need adjustment to match your locale and preferences
**Default value '%Y-%m-%d'**.
## journey
The object containing configurations specific for sequence diagrams
### diagramMarginX
margin to the right and left of the sequence diagram.
**Default value 50**.
### diagramMarginY
margin to the over and under the sequence diagram.
**Default value 10**.
### actorMargin
Margin between actors.
**Default value 50**.
### width
Width of actor boxes
**Default value 150**.
### height
Height of actor boxes
**Default value 65**.
### boxMargin
Margin around loop boxes
**Default value 10**.
### boxTextMargin
margin around the text in loop/alt/opt boxes
**Default value 5**.
### noteMargin
margin around notes.
**Default value 10**.
### messageMargin
Space between messages.
**Default value 35**.
### messageAlign
Multiline message alignment. Possible values are:
- left
- center **default**
- right
### bottomMarginAdj
Depending on css styling this might need adjustment.
Prolongs the edge of the diagram downwards.
**Default value 1**.
### useMaxWidth
when this flag is set the height and width is set to 100% and is then scaling with the
available space if not the absolute space required is used.
**Default value true**.
### rightAngles
This will display arrows that start and begin at the same node as right angles, rather than a curve
**Default value false**.
## er
The object containing configurations specific for entity relationship diagrams
### diagramPadding
The amount of padding around the diagram as a whole so that embedded diagrams have margins, expressed in pixels
### layoutDirection
Directional bias for layout of entities. Can be either 'TB', 'BT', 'LR', or 'RL',
where T = top, B = bottom, L = left, and R = right.
### minEntityWidth
The mimimum width of an entity box, expressed in pixels
### minEntityHeight
The minimum height of an entity box, expressed in pixels
### entityPadding
The minimum internal padding between the text in an entity box and the enclosing box borders, expressed in pixels
### stroke
Stroke color of box edges and lines
### fill
Fill color of entity boxes
### fontSize
Font size (expressed as an integer representing a number of pixels)
## render
Function that renders an svg with a graph from a chart definition. Usage example below.
```js
mermaidAPI.initialize({
startOnLoad:true
});
$(function(){
const graphDefinition = 'graph TB\na-->b';
const cb = function(svgGraph){
console.log(svgGraph);
};
mermaidAPI.render('id1',graphDefinition,cb);
});
```
### Parameters
- `id` the id of the element to be rendered
- `_txt`
- `cb` callback which is called after rendering is finished with the svg code as inparam.
- `container` selector to element in which a div with the graph temporarily will be inserted. In one is
provided a hidden div will be inserted in the body of the page instead. The element will be removed when rendering is
completed.
- `txt` the graph definition
##
## mermaidAPI configuration defaults
<pre>
&lt;script>
var config = {
theme:'default',
logLevel:'fatal',
securityLevel:'strict',
startOnLoad:true,
arrowMarkerAbsolute:false,
flowchart:{
htmlLabels:true,
curve:'linear',
},
sequence:{
diagramMarginX:50,
diagramMarginY:10,
actorMargin:50,
width:150,
height:65,
boxMargin:10,
boxTextMargin:5,
noteMargin:10,
messageMargin:35,
messageAlign:'center',
mirrorActors:true,
bottomMarginAdj:1,
useMaxWidth:true,
rightAngles:false,
showSequenceNumbers:false,
},
gantt:{
titleTopMargin:25,
barHeight:20,
barGap:4,
topPadding:50,
leftPadding:75,
gridLineStartPadding:35,
fontSize:11,
fontFamily:'"Open-Sans", "sans-serif"',
numberSectionStyles:4,
axisFormat:'%Y-%m-%d',
}
};
mermaid.initialize(config);
&lt;/script>
</pre>
[1]: https://github.com/knsv/mermaid/blob/master/docs/mermaidAPI.md#render
[2]: https://github.com/knsv/mermaid/blob/master/docs/mermaidAPI.md#mermaidapi-configuration-defaults

View File

@ -1,19 +1,23 @@
# A basic mermaid User-Guide for Beginners
**Edit this Page** [![N|Solid](./img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/n00b-gettingStarted.md)
Creating diagrams and charts, using mermaid code is simple.
Creating diagrams and charts using mermaid code is simple.
The code is turned into a diagram in the web page with the use of a mermaid renderer.
But how is the code turned into a diagram in a web page? This is done with the use of a mermaid renderer.
The mermaid renderer is a piece of javascript that parses mermaid definitions, when called.
This then renders a diagram based on that code in SVG, alternatively it
Thankfully the mermaid renderer is very accessible, in essence it is a piece of javascript that can be called.
Most web browsers, such as Firefox, Chrome and Safari, can render mermaid, Internet Explorer however cannot.
Most widely used web browsers, such as Firefox, Chrome and Safari, can render mermaid, Internet Explorer however cannot. The web browser also needs access to the online mermaid renderer which it downloads from https://cdn.jsdelivr.net/npm/mermaid
## For beginners, there are four relatively easy ways you can use mermaid:
1. Using the mermaid [live editor](https://mermaid-js.github.io/mermaid-live-editor/). For some popular video tutorials on the live editor go to [Overview](./n00b-overview.md).
2. Using one of the many [mermaid plugins](https://mermaid-js.github.io/mermaid/#/integrations).
3. Hosting mermaid on a webpage, with an absolute link.
4. Downloading mermaid and hosting it on your Web Page.
# For beginners, there are three relatively easy ways you can use mermaid:
1. Using the mermaid [live editor](https://mermaid-js.github.io/mermaid-live-editor/)
2. Using a mermaid plugin, such as that for Confluence or [Atom](https://atom.io/packages/atom-mermaid).
3. Calling mermaid renderer with HTML, deployed in a friendly browser.
# Following either of these examples, you can get started with creating your own diagrams using mermaid code.
**Notes**: More in depth information can be found on [Usage](./usage.md).
.
# Following any of these examples, you can get started with creating your own diagrams using mermaid code.
## 1. The mermaid live editor:
@ -21,26 +25,29 @@ Most widely used web browsers, such as Firefox, Chrome and Safari, can render me
In the `Code` section one can write or edit raw mermaid code, and instantly `Preview` the rendered result on the panel beside it.
**This is a great way to learn how to define a mermaid diagram.**
For some popular video tutorials on the live editor go to [Overview](./n00b-overview.md).
![Flowchart](./img/n00b-liveEditor.png)
**Notes:**
You can also copy the code from the code section and paste it into either a mermaid plugin or in inside an html file, which will be taught in numbers 2 and 3.
It is also an easier way to develop diagrams. You can also click "Copy Markdown" to copy the markdown code for the diagram, that can then be pasted directly into your documentation.
You can also click "Copy Markdown" to copy the markdown code for the diagram, that can then be pasted directly into your documentation.
![Flowchart](./img/liveEditorOptions.png)
The `Mermaid configuration` is for controlling mermaid behaviour. An easy introduction to mermaid configuration is found in the [Advanced usage](n00b-advanced.md) section. A complete configuration reference cataloguing default values is found on the [mermaidAPI](mermaidAPI.md) page.
The `Mermaid configuration` is for controlling mermaid behaviour. An easy introduction to mermaid configuration is found in the [Advanced usage](n00b-advanced.md) section. A complete configuration reference cataloguing default values is found on the [mermaidAPI](https://mermaid-js.github.io/mermaid/#/Setup) page.
## 2. Using mermaid plugins:
Thanks to the growing popularity of mermaid, many plugins already exist which incorporate a mermaid renderer. An extensive list can be found [here](integrations.md).
Thanks to the growing popularity of mermaid, many plugins already exist which incorporate a mermaid renderer. An extensive list can be found [here](./integrations.md).
One example in the list is the [Atlassian Confluence mermaid plugin](https://marketplace.atlassian.com/apps/1214124/mermaid-plugin-for-confluence?hosting=server&tab=overview)
When the mermaid plugin is installed on a Confluence server, one can insert a mermaid object into any Confluence page.
# Here is a step by step process for using the mermaid-Confluence plugin:
### Here is a step by step process for using the mermaid-Confluence plugin:
---
@ -67,17 +74,18 @@ When the mermaid plugin is installed on a Confluence server, one can insert a me
![Flowchart](./img/n00b-Confluence4.png)
---
## The following are two ways of hosting mermaid on a webpage.
**This is covered in greater detail in the [Usage section](https://mermaid-js.github.io/mermaid/#/usage)**
## 3. mermaid using any web server (or just a browser):
## 3. Using the Mermaid API: The quick and dirty way of deploying mermaid
This method can be used with any common web server. Apache, IIS, nginx, node express [...], you pick your favourite.
We do not need to install anything on the server, apart from a program (like Notepad++) that can generate an html file, which is then deployed by a web browser (such as Firefox, Chrome, Safari, but not Internet Explorer).
So if you want to really simplify things when testing this out, don't use a web server at all but just create the file locally and drag it into your browser window. It is the browser which does all the work of rendering mermaid!
So if you want to really simplify things when testing this out, don't use a web server at all but just create an HTML file locally and drag it into your browser window. The browser will do the work of rendering the mermaid diagrams according to the descriptions you've given!
# Here are instructions for creating an html file with mermaid code:
# Note that all this is written in the html `<body>` section of the web page.
### Note that all this is written in the html `<body>` section of the web page.
When writing the html file, we give the web browser three instructions inside the html code:
@ -85,23 +93,22 @@ a. A reference for fetching the online mermaid renderer, which is written in Jav
b. The mermaid code for the diagram we want to create.
c. The `mermaid.initialize()` command to start the rendering process.
c. The `mermaid.initialize()` API call to start the rendering process.
## This is what needs to go into the html file (and all of them are important), for the mermaidAPI to render the diagrams:
This is what needs to go into the html file:
# a. The reference to the mermaid renderer has to be contained in a `<script src>` tag like so:
### a. A reference to the address of the `mermaid.js` or the `mermaid.min.js` file has to be contained in a `<script src>` tag like so:
```
<body>
<script src="https://cdn.jsdelivr.net/npm/mermaid@8.4.0/dist/mermaid.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
</body>
```
# b. The embedded mermaid code is similarly placed inside a `<div>` tag:
### b. The embedded mermaid diagram definition needs to be contains inside a `<div>` tag that signifies that it is a mermaid diagram:
```
<body>
@ -114,22 +121,27 @@ This is what needs to go into the html file:
</div>
</body>
```
(take note that every mermaid chart/graph/diagram, has to have separate `<div>` tags.)
**Notes**: every mermaid chart/graph/diagram definition, has to have separate `<div>` tags.
# c. When initializing mermaid using `mermaid.initialize()`, mermaid takes all the `<div class="mermaid">` tags it can find in the html body and starts to render them one by one. This is done like so:
### c. The `mermaid.initialize()` API call
`mermaid.initialize()` calls take all the definitions contained in `<div class="mermaid">` tags it can find in the html body and starts to render them one by one. It is called this way:
```
<body>
<script>mermaid.initialize({startOnLoad:true});</script>
</body>
```
**Notes**: It is good practice to keep the `mermaid.initialize()` API call right next the `mermaid.min.js` `script` tag.
`startOnLoad` is a parameter that can optionally be changed to false, this would then prevent mermaid from immediately rendering upon loading.
### If the three steps mentioned are followed you will end up with something like this:
# *Finally*
# If the three steps mentioned are followed you will end up with something like this:
```
<html>
<body>
<script src="https://cdn.jsdelivr.net/npm/mermaid@8.4.0/dist/mermaid.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
<script>mermaid.initialize({startOnLoad:true});</script>
Here is one mermaid diagram:
@ -150,16 +162,80 @@ This is what needs to go into the html file:
</body>
</html>
```
# Save this to a html file and fetch it with a browser from the web server (or just drag it into your web browser window) and voila!
**Notes**: This has to be saved in an `HTML` file and opened with a browser.
---
## 4. Calling mermaid from a relative link.
This method is similar to 3, if only a little more involved. The difference may be very subtle even, but it offers its own advantages, mainly in speed.
1. install node v10 or 12, which would have npm
2. download yarn using npm by entering the command below:
npm install -g yarn
3. After yarn installs, enter the following command:
yarn add mermaid
4. After downloading mermaid, you can then open the mermaid file youve downloaded and go to the `dist` folder.
5. Find the `mermaid.min.js` file,
a. select the file.
b. press the shift key and right click on it
c. select copy as path from the options.
6. Paste it within the `script` tag as the `src`.
```
<script src="Paste the mermaid.min.js file address here"></script>
<script>mermaid.initialize({startOnLoad:true});</script>
```
7. It should look something like this
```
<script src="C:\Users\myPC\mermaid\dist\mermaid.js"></script>
<script>mermaid.initialize({startOnLoad:true});</script>
```
8. Add the graph and diagram definitions as you would in number 3.
a. be mindful of the `div` tags.
9. Save, load/edit your HTML file to your liking.
**Note** placing the HTML file on the same folder the `mermaid` file you've downloaded is a good practice and allows you to shorten the address on the `src` section.
**As seen here, in this full example:**
```
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
<div class="mermaid">
graph LR
A --- B
B-->C[fa:fa-ban forbidden]
B-->D(fa:fa-spinner);
</div>
<div class="mermaid">
graph TD
A[Client] --> B[Load Balancer]
B --> C[Server1]
B --> D[Server2]
</div>
<script src="C:\Users\MyPC\mermaid\dist\mermaid.js"></script>
<script>mermaid.initialize({startOnLoad:true});</script>
</body>
</html>
```
**Three additional comments from Knut Sveidqvist, creator of mermaid:**
- In early versions of mermaid, the `<script src>` tag was invoked in the `<head>` part of the web page. Nowdays we can place it directly in `<body>` as seen above. However, older parts of the documentation frequently reflects the previous way which still works.
- We initialize the mermaid rendering with `mermaid.initialize()` directly in the html code. In principle this could be done through placing `mermaid.initialize()` inside of `mermaid.min.js`. We would then eliminate the need for this explicit line in the html. However, there are use cases where we do want to separate the two steps. Sometimes we want full control over when we start looking for `<div>`tags inside the web page with `mermaid.initialize()`, for example when we think that all `<div>` tags may not have been loaded by the time `mermaid.min.js` runs.
- In the example above, `mermaid.min.js` is called using an absolute path. Even worse, the example includes the mermaid version number which of course will change as time goes by. However, the example makes it easy to understand what is going on - even though it is perhaps doomed in a way we do not want in a production environment. When going from testing mermaid out to getting serious with it, I would suggest one of the following approaches for calling `mermaid.min.js`:
- In the third method, `mermaid.min.js` is called using an absolute path. Even worse, the example includes the mermaid version number which of course will change as time goes by. However, the example makes it easy to understand what is going on - even though it is perhaps doomed in a way we do not want in a production environment. When going from testing mermaid out to getting serious with it, I would suggest one of the following approaches for calling `mermaid.min.js`:
1. If you do not enter a specific version, you automatically get the latest one.
2. If you really need a specific version, hard code it (this is rare but it happens).

View File

@ -1,8 +1,27 @@
# Overview for n00bs
# Overview for Beginners
**Edit this Page** [![N|Solid](./img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/n00b-overview.md)
mermaid is a tool that aims to make diagrams and flowcharts for documentation, easier.
## There is no explanation like a Good Diagram
with mermaid, diagrams can be created through comments like this in a script:
A picture is worth a thousand words, a good diagram would be worth more. There is no disputing that they are indeed very useful. Yet very few people use them, even fewer still do so, for documentation.
mermaid aims to change that.
## Creating and Maintaining Diagrams should not be an expensive and frustrating process.
Anyone who has used Visio, or (God Forbid) Excel to make a Gantt Chart, knows how hard it is to make, edit and maintain good visualizations.
In an environment of constantly changing information , diagrams/charts become obsolete/inaccurate very fast. This hobbles the information transfer and productivity in teams.
# Doc Rot kills Diagrams
The fast setting Doc-Rot in diagrams makes it quite hard to rationalize taking hours in a desktop application, to produce a diagram that you would need to recreate again the following week in order to account for updates and changes in the app you are documenting. Yet that is often the reality for diagrams and charts and the people who make them.
mermaid seeks to change that. mermaid is a javascript based tool that utilizes a markdown inspired syntax to generate documentation, which is actually quicker, less complicated and more convenient than most traditional diagramming software. This is a relatively straightforward solution to a major hurdle in software teams.
# The primary objective of mermaid is to help in addressing the problem of Doc Rot.
With mermaid, diagrams can be created through comments like this in a script:
```
graph TD
@ -15,15 +34,41 @@ And they are rendered into this and made part of the documentation:
![Flowchart](./img/n00b-firstFlow.png)
Most of the similar visuals that you might need to create can be scripted in a similar way, with a varitety of different symbols and chart types available.
Since the diagram source is text based, it can be part of production scripts (and other pieces of code). So less time needs be spent on documenting as a separate task.
## Advantages of Using Mermaid
Comparing with Visio and similar applications, mermaid is a really fast way to create good visualizations. This is especially apparent when editing a complex visualisations, a process that usually takes hours in a desktop application, but only takes minutes (or even less if generation has been scripted) with mermaid.
- The Advantages of mermaid include its ease of generation, modification and rendering.
- The number of integrations that it has.
- It is a package that can be deployed to create
mermaid can potentially cut down the amount of time and effort spent on the process of creating diagrams, to a fraction of what you usually put in.
However, a lot of the mermaid documentation is geared to professional frontend developers, presuming a skill set which I simply do not have.
## Diagramming and charting is a gigantic waste of developer time, but not having diagrams ruins productivity.
If you need some basic instructions and introductions, here are a few good places to start:
mermaid can cut down the amount of time, effort and the learning curve that is associated with creating diagrams and charts, by a wide margin.
For information on how to use mermaid, click [here](https://mermaid-js.github.io/mermaid/#/n00b-gettingStarted), or you can try out the mermaid [live editor](https://mermaid-js.github.io/mermaid-live-editor/), alternatively, you could also view the [integrations and uses](https://github.com/mermaid-js/mermaid/blob/develop/docs/integrations.md) for mermaid.
Because, the text base for diagrams allows for it to be updated easily, it can also be made part of production scripts (and other pieces of code). So less time needs be spent on documenting, as a separate task.
## mermaid helps Documentation catch up with Development, in quickly changing projects.
Being based on markdown, mermaid can be used, not only by accomplished front-end developers, but by most computer savvy people to render simple diagrams, at much faster speeds.
In fact one can pick up the syntax for it quite easily from the examples given and there are many tutorials in the internet.
## mermaid is for everyone.
For information on how to use mermaid, click [here](https://mermaid-js.github.io/mermaid/#/n00b-gettingStarted).
You can try out the mermaid [live editor](https://mermaid-js.github.io/mermaid-live-editor/).
Alternatively, you could also view the [integrations and uses](https://mermaid-js.github.io/mermaid/#/./integrations).
# For anyone who may need video tutorials, here is a list of beginner friendly introductions:
https://www.youtube.com/watch?v=SQ9QmuTHuSI&t=438s
https://www.youtube.com/watch?v=5RQqht3NNSE
https://www.youtube.com/watch?v=7_2IroEs6Is&t=207s
https://www.youtube.com/watch?v=9HZzKkAqrX8
https://www.youtube.com/watch?v=7_2IroEs6Is&t=207s
https://www.youtube.com/watch?v=9HZzKkAqrX8

View File

@ -1,6 +1,30 @@
## Diagram syntax reference
## Diagram syntax
**Edit this Page** [![N|Solid](./img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/n00b-syntaxReference.md)
If you are new to mermaid, read the [Getting Started](n00b-gettingStarted.md) and [Overview](n00b-overview.md) sections, to learn the basics of mermaid.
Video Tutorials can be found at the bottom of the Overview Section.
This section is a list of diagram types supported by mermaid. Below is a list of links to aricles that explain the syntax of the diagrams or charts that 0can be called.
They also detail how diagrams can be defined, or described in the manner with which the diagram is to be rendered by the renderer.
### The benefits of text based diagramming are its speed and modifiability. mermaid allows for easy maintenance and modification of diagrams. This means your diagrams will always be up to date and closely follow your code and improve your documentation.
## mermaid tag:
These Diagram Definitions can be entered within a \<div class=mermaid> tag.
like so :
```
<div class="mermaid">
graph LR
A --- B
B-->C[fa:fa-ban forbidden]
B-->D(fa:fa-spinner);
</div>
```
## mermaid Live Editor
These definitions can also be entered into the [mermaid live editor](https://mermaid-js.github.io/mermaid-live-editor), to render them immediately.
This would then offer
Having already [gotten started](n00b-gettingStarted.md), existing diagram syntax documentation was easy enough to follow even for a n00b like me..
- [Flowchart](flowchart.md)
- [Sequence diagram](sequenceDiagram.md)
@ -8,4 +32,6 @@ Having already [gotten started](n00b-gettingStarted.md), existing diagram syntax
- [State Diagram](stateDiagram.md)
- [Gantt](gantt.md)
- [Pie Chart](pie.md)
- [Entity Relationship Diagram](entityRelationshipDiagram.md)
- [User Journey Diagram](user-journey.md)
- [Directives](directives.md)

View File

@ -1,5 +1,7 @@
# Pie chart diagrams
**Edit this Page** [![N|Solid](./img/GitHub-Mark-32px.png)](./pie.md)
> A pie chart (or a circle chart) is a circular statistical graphic, which is divided into slices to illustrate numerical proportion. In a pie chart, the arc length of each slice (and consequently its central angle and area), is proportional to the quantity it represents. While it is named for its resemblance to a pie which has been sliced, there are variations on the way it can be presented. The earliest known pie chart is generally credited to William Playfair's Statistical Breviary of 1801
-Wikipedia

View File

@ -1,5 +1,7 @@
# Sequence diagrams
**Edit this Page** [![N|Solid](./img/GitHub-Mark-32px.png)](./sequenceDiagram.md)
> A Sequence diagram is an interaction diagram that shows how processes operate with one another and in what order.
Mermaid can render sequence diagrams.
@ -16,6 +18,10 @@ sequenceDiagram
John-->>Alice: Great!
```
## A note on nodes, the word "end" could potentially break the diagram, due to the way that the mermaid language is scripted.
## If unavoidable, one must use parentheses(), quotation marks "", or brackets {},[], to enclose the word "end". i.e : (end), [end], {end}.
## Syntax
### Participants
@ -506,8 +512,11 @@ mermaid.sequenceConfig = {
| bottomMarginAdj | Adjusts how far down the graph ended. Wide borders styles with css could generate unwanted clipping which is why this config param exists. | 1 |
| actorFontSize | Sets the font size for the actor's description | 14 |
| actorFontFamily | Sets the font family for the actor's description | "Open-Sans", "sans-serif" |
| actorFontWeight | Sets the font weight for the actor's description | "Open-Sans", "sans-serif" |
| noteFontSize | Sets the font size for actor-attached notes | 14 |
| noteFontFamily | Sets the font family for actor-attached notes | "trebuchet ms", verdana, arial |
| noteFontWeight | Sets the font weight for actor-attached notes | "trebuchet ms", verdana, arial |
| noteAlign | Sets the text alignment for text in actor-attached notes | center |
| messageFontSize | Sets the font size for actor<->actor messages | 16 |
| messageFontFamily | Sets the font family for actor<->actor messages | "trebuchet ms", verdana, arial |
| messageFontWeight | Sets the font weight for actor<->actor messages | "trebuchet ms", verdana, arial |

View File

@ -1,5 +1,7 @@
# State diagrams
**Edit this Page** [![N|Solid](./img/GitHub-Mark-32px.png)](./stateDiagram.md)
> "A state diagram is a type of diagram used in computer science and related fields to describe the behavior of systems. State diagrams require that the system described is composed of a finite number of states; sometimes, this is indeed the case, while at other times this is a reasonable abstraction." Wikipedia
Mermaid can render state diagrams. The syntax tries to be compliant with the syntax used in plantUml as this will make it easier for users to share diagrams between mermaid and plantUml.

3
docs/theme.css Normal file

File diff suppressed because one or more lines are too long

10
docs/theme_themed.css Normal file

File diff suppressed because one or more lines are too long

265
docs/theming.md Normal file
View File

@ -0,0 +1,265 @@
# Theming
Mermaid as a system for theming in place. With it a site integrator can override a vast majority of attributes used when rendering a diagram.
The settings for a theme can be set globally for the site with the initialize call. The example below highlights how that can look:
```
// example
```
It is also possible to override theme settings locally in a diagram using directives.
```
%%{init: {'theme':'base'}}%%
graph TD
a --> b
```
The easiest way to make a custom theme is to start with the base theme, the theme named base and just modify these variables:
* primaryColor - the base color for the theme
More specific color variables it is possible to change:
* lineColor
* textColor
Here is an example of a showcase flowchart with theme set to base, with the default variables set:
```mermaid
%%{init: {'theme':'base'}}%%
graph TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[/Another/]
C ==>|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
subgraph section
C
D
E
F
G
end
```
Here is an example of overriding the primary color and giving everything a little different look.
```mermaid
%%{init: {'theme':'base', 'themeVariables': {primaryColor: '#ff0000'}}%%
graph TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[/Another/]
C ==>|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
subgraph section
C
D
E
F
G
end
```
As the theming engine is using color codes to calculate values from the base color/base colors it needs proper color values contrain the actual color data. Aliases like color names is not supported so for instance, the color value 'red' will not work but '#ff0000' will work.
## Showcases
When adjusting a theme it might be helpful to look at the theme with these diagrams to evaluate that everything is visiable and looks good.
### flowchart
```
%%{init: {'securityLevel': 'loose', 'theme':'base'}}%%
graph TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[/Another/]
C ==>|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
subgraph section
C
D
E
F
G
end
```
```mermaid
%%{init: {'securityLevel': 'loose', 'theme':'base'}}%%
graph TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[/Another/]
C ==>|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
subgraph section
C
D
E
F
G
end
```
### flowchart (beta)
```mermaid
%%{init: {'securityLevel': 'loose', 'theme':'base'}}%%
flowchart TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[Another]
C ==>|One| D[Laptop]
C x--x|Two| E[iPhone]
C o--o|Three| F[fa:fa-car Car]
subgraph section
C
D
E
F
G
end
```
### Sequence diagram
```mermaid
%%{init: {'securityLevel': 'loose', 'theme':'base'}}%%
sequenceDiagram
autonumber
par Action 1
Alice->>John: Hello John, how are you?
and Action 2
Alice->>Bob: Hello Bob, how are you?
end
Alice->>+John: Hello John, how are you?
Alice->>+John: John, can you hear me?
John-->>-Alice: Hi Alice, I can hear you!
Note right of John: John is perceptive
John-->>-Alice: I feel great!
loop Every minute
John-->Alice: Great!
end
```
### Gantt
```mermaid
gantt
dateFormat :YYYY-MM-DD
title Adding GANTT diagram functionality to mermaid
excludes :excludes the named dates/days from being included in a charted task..
section A section
Completed task :done, des1, 2014-01-06,2014-01-08
Active task :active, des2, 2014-01-09, 3d
Future task : des3, after des2, 5d
Future task2 : des4, after des3, 5d
section Critical tasks
Completed task in the critical line :crit, done, 2014-01-06,24h
Implement parser and jison :crit, done, after des1, 2d
Create tests for parser :crit, active, 3d
Future task in critical line :crit, 5d
Create tests for renderer :2d
Add to mermaid :1d
section Documentation
Describe gantt syntax :active, a1, after des1, 3d
Add gantt diagram to demo page :after a1 , 20h
Add another diagram to demo page :doc1, after a1 , 48h
section Last section
Describe gantt syntax :after doc1, 3d
Add gantt diagram to demo page :20h
Add another diagram to demo page :48h
```
### State diagram
```mermaid
%%{init: {'securityLevel': 'loose', 'theme':'base'}}%%
stateDiagram
[*] --> Active
state Active {
[*] --> NumLockOff
NumLockOff --> NumLockOn : EvNumLockPressed
NumLockOn --> NumLockOff : EvNumLockPressed
--
[*] --> CapsLockOff
CapsLockOff --> CapsLockOn : EvCapsLockPressed
CapsLockOn --> CapsLockOff : EvCapsLockPressed
--
[*] --> ScrollLockOff
ScrollLockOff --> ScrollLockOn : EvCapsLockPressed
ScrollLockOn --> ScrollLockOff : EvCapsLockPressed
}
state SomethingElse {
A --> B
B --> A
}
Active --> SomethingElse
note right of SomethingElse : This is the note to the right.
SomethingElse --> [*]
```
### State diagram (beta)
```mermaid
%%{init: {'securityLevel': 'loose', 'theme':'base'}}%%
stateDiagram-v2
[*] --> Active
state Active {
[*] --> NumLockOff
NumLockOff --> NumLockOn : EvNumLockPressed
NumLockOn --> NumLockOff : EvNumLockPressed
--
[*] --> CapsLockOff
CapsLockOff --> CapsLockOn : EvCapsLockPressed
CapsLockOn --> CapsLockOff : EvCapsLockPressed
--
[*] --> ScrollLockOff
ScrollLockOff --> ScrollLockOn : EvCapsLockPressed
ScrollLockOn --> ScrollLockOff : EvCapsLockPressed
}
state SomethingElse {
A --> B
B --> A
}
Active --> SomethingElse2
note right of SomethingElse2 : This is the note to the right.
SomethingElse2 --> [*]
```
### Entity Relations diagram
```mermaid
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"
```
### User journet diagram
```mermaid
journey
title My working day
section Go to work
Make tea: 5: Me
Go upstairs: 3: Me
Do work: 1: Me, Cat
section Go home
Go downstairs: 5: Me
Sit down: 5: Me
```

View File

@ -1,12 +1,9 @@
# Usage
**Edit this Page** [![N|Solid](./img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/usage.md)
## Installation
mermaid is a javascript tool that makes use of a markdown based syntax to render customizable diagrams and charts, for greater speed and ease.
### npm package
```
yarn add mermaid
```
mermaid was made to 0help Documentation catch up with Development, in quickly changing projects.
### CDN
@ -14,65 +11,57 @@ https://unpkg.com/mermaid/
Please note that you can switch versions through the dropdown box at the top right.
## Using mermaid
## Simple usage on a web page
For the majority of beginners, using the live editor or suppoting mermaid on a webpage would cover their uses for mermaid.
The easiest way to integrate mermaid on a web page requires two elements:
1. Inclusion of the mermaid framework in the html page using a script tag
2. A graph definition on the web page
## Installing and Hosting mermaid on a webpage
If these things are in place mermaid listens to the page load event and when fired (when the page has loaded) it will
locate the graphs on the page and transform them to svg files.
### Using the npm package
### Include mermaid on your web page:
```
1.You will need to insall node v10 or 12, which would have npm.
```html
<script src="mermaid.min.js"></script>
<script>mermaid.initialize({startOnLoad:true});</script>
2. download yarn using npm.
3. enter the following command:
yarn add mermaid
4. At this point, you can add mermaid as a dev dependency using this command:
yarn add --dev mermaid
5. Alternatively, you can also deploy mermaid using the script tag in an HTML file with mermaid diagram descriptions.
as is shown in the example below
```
Further down on your page mermaid will look for tags with `class="mermaid"`. From these tags mermaid will try to
read the chart definiton and replace it with the svg chart.
## Hosting mermaid on a web page.
**Notes**: This topic explored in greater depth in the [User Guide for Beginners](./n00b-gettingStarted.md)
### Define a chart like this:
The easiest way to integrate mermaid on a web page requires three elements:
```html
1. Inclusion of the mermaid address in the html page using a `script` tag, in the `src` section.Example:
`<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>`
2. The `mermaidAPI` call, in a separate `script` tag. Example:
`<script>mermaid.initialize({startOnLoad:true});</script>`
3. A graph definition, inside `<div>` tags labeled `class=mermaid`. Example:
```
<div class="mermaid">
CHART DEFINITION GOES HERE
graph LR
A --- B
B-->C[fa:fa-ban forbidden]
B-->D(fa:fa-spinner);
</div>
```
Would end up like this:
**If these things are in place mermaid starts at the page load event and when fired (when the page has loaded) it will
locate the graph definitions inside the `div` tags with `class="mermaid"` on the page and transform them to svg charts or diagrams.**
```html
<div class="mermaid" id="mermaidChart0">
<svg>
Chart ends up here
</svg>
</div>
```
An id attribute is also added to mermaid tags without one.
### To enable click event and tags in nodes
In version 8.2 a security improvement was introduced. A `securityLevel` configuration was introduced which sets the level of trust to be used on the parsed diagrams.
* **true**: (default) tags in text are encoded, click functionality is disabled
* false: tags in text are allowed, click functionality is enabled
⚠️ **Note** : This changes the default behaviour of mermaid so that after upgrade to 8.2, if the `securityLevel` is not configured, tags in flowcharts are encoded as tags and clicking is prohibited.
If your application is taking resposibility for the diagram source security you can set the `securityLevel` accordingly. By doing this clicks and tags are again allowed.
```javascript
mermaidAPI.initialize({
securityLevel: 'loose'
});
```
### Simple full example:
## Simple full example:
```html
<!DOCTYPE html>
@ -87,12 +76,50 @@ If your application is taking resposibility for the diagram source security you
B-->C[fa:fa-ban forbidden]
B-->D(fa:fa-spinner);
</div>
<script src="mermaid.min.js"></script>
<script>mermaid.initialize({startOnLoad:true});</script>
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
<script>mermaid.initialize({startOnLoad:true});</script>
</body>
</html>
```
## Notes:
An id attribute is also added to mermaid tags without one.
Mermaid can load multiple diagrams, in the same page.
### Try it out, save this code as HTML and load it using any browser.(Please don't use Internet Explorer though.)
## To enable click event and tags in nodes
A `securityLevel` configuration has to first be cleared, `securityLevel` sets the level of trust for the parsed diagrams. This was introduce in version 8.2 as a security improvement, aimed at preventing malicious use.
## securityLevel
| Parameter | Description | Type | Required | Values |
| ------------- | --------------------------------- | ------ | -------- | ------------------------- |
| securitylevel | Level of trust for parsed diagram | String | Required | Strict, Loose, antiscript |
\*\*Notes:
- **strict**: (**default**) tags in text are encoded, click functionality is disabeled
- **loose**: tags in text are allowed, click functionality is enabled
- **antiscript**: html tags in text are allowed, (only script element is removed), click functionality is enabled
⚠️ **Note** : This changes the default behaviour of mermaid so that after upgrade to 8.2, if the `securityLevel` is not configured, tags in flowcharts are encoded as tags and clicking is prohibited.
If you are taking resposibility for the diagram source security you can set the `securityLevel` to a value of your choosing . By doing this clicks and tags are again allowed.
## To chage `securityLevel` with `mermaidAPI.initialize`:
```javascript
mermaidAPI.initialize({
securityLevel: 'loose'
});
```
### Labels out of bounds
If you use dynamically loaded fonts that are loaded through CSS, such as Google fonts, mermaid should wait for the
@ -120,6 +147,7 @@ If your page has other fonts in its body those might be used instead of the merm
font-family: 'trebuchet ms', verdana, arial;
}
```
# This likely requires a `script.js` file, separate from the `HTML`.
### Calling `mermaid.init`
@ -350,6 +378,7 @@ mermaid_config.startOnLoad = true;
## Using the mermaid.init call
#
Is it possible to set some configuration via the mermaid object. The two parameters that are supported using this
approach are:

View File

@ -1,5 +1,5 @@
# User Journey Diagram
**Edit this Page** [![N|Solid](./img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/user-journey.md)
> User journeys describe at a high level of detail exactly what steps different users take to complete a specific task within a system, application or website. This technique shows the current (as-is) user workflow, and reveals areas of improvement for the to-be workflow. (Wikipedia)
Mermaid can render user journey diagrams:

View File

@ -1,6 +1,6 @@
{
"name": "mermaid",
"version": "8.5.2",
"version": "8.6.4",
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
"main": "dist/mermaid.core.js",
"keywords": [
@ -16,7 +16,7 @@
"build:development": "webpack --progress --colors",
"build:production": "yarn build:development -p --config webpack.config.prod.babel.js",
"build": "yarn build:development && yarn build:production",
"postbuild": "documentation build src/mermaidAPI.js --shallow -f md --markdown-toc false -o docs/mermaidAPI.md",
"postbuild": "documentation build src/mermaidAPI.js src/config.js --shallow -f md --markdown-toc false -o docs/Setup.md",
"build:watch": "yarn build --watch",
"minify": "minify ./dist/mermaid.js > ./dist/mermaid.min.js",
"release": "yarn build",
@ -29,7 +29,6 @@
"test": "yarn lint && jest src/.*",
"test:watch": "jest --watch src",
"prepublishOnly": "yarn build && yarn test && yarn e2e",
"prepush": "yarn test",
"prepare": "yarn build"
},
"repository": {
@ -50,16 +49,16 @@
},
"dependencies": {
"@braintree/sanitize-url": "^3.1.0",
"crypto-random-string": "^3.0.1",
"d3": "^5.7.0",
"dagre": "^0.8.4",
"dagre-d3": "^0.6.4",
"entity-decode": "^2.0.2",
"graphlib": "^2.1.7",
"he": "^1.2.0",
"khroma": "^1.1.0",
"minify": "^4.1.1",
"moment-mini": "^2.22.1",
"scope-css": "^1.2.1"
"stylis": "^3.5.2"
},
"devDependencies": {
"@babel/core": "^7.2.2",
@ -106,5 +105,10 @@
"sideEffects": [
"**/*.css",
"**/*.scss"
]
],
"husky": {
"hooks": {
"pre-push": "yarn test"
}
}
}

File diff suppressed because it is too large Load Diff

52
src/config.spec.js Normal file
View File

@ -0,0 +1,52 @@
/* eslint-env jasmine */
import configApi from './config';
describe('when working with site config', function() {
beforeEach(() => {
configApi.reset(configApi.defaultConfig);
});
it('should set site config and config properly', function() {
let config_0 = { foo: 'bar', bar: 0 };
configApi.setSiteConfig(config_0);
let config_1 = configApi.getSiteConfig();
let config_2 = configApi.getConfig();
expect(config_1.foo).toEqual(config_0.foo);
expect(config_1.bar).toEqual(config_0.bar);
expect(config_1).toEqual(config_2);
});
it('should set config and respect secure keys', function() {
let config_0 = { foo: 'bar', bar: 0, secure: [...configApi.defaultConfig.secure, 'bar'] };
configApi.setSiteConfig(config_0);
let config_1 = { foo: 'baf', bar: 'foo'};
configApi.setConfig(config_1);
let config_2 = configApi.getConfig();
expect(config_2.foo).toEqual(config_1.foo);
expect(config_2.bar).toEqual(0); // Should be siteConfig.bar
});
it('should set reset config properly', function() {
let config_0 = { foo: 'bar', bar: 0};
configApi.setSiteConfig(config_0);
let config_1 = { foo: 'baf'};
configApi.setConfig(config_1);
let config_2 = configApi.getConfig();
expect(config_2.foo).toEqual(config_1.foo);
configApi.reset();
let config_3 = configApi.getConfig();
expect(config_3.foo).toEqual(config_0.foo);
let config_4 = configApi.getSiteConfig();
expect(config_4.foo).toEqual(config_0.foo);
});
it('should set global reset config properly', function() {
let config_0 = { foo: 'bar', bar: 0};
configApi.setSiteConfig(config_0);
let config_1 = configApi.getSiteConfig();
expect(config_1.foo).toEqual(config_0.foo);
let config_2 = configApi.getConfig();
expect(config_2.foo).toEqual(config_0.foo);
configApi.reset(configApi.defaultConfig);
let config_3 = configApi.getSiteConfig();
expect(config_3.foo).toBeUndefined();
let config_4 = configApi.getConfig();
expect(config_4.foo).toBeUndefined();
});
});

View File

@ -84,6 +84,7 @@ This is set by the renderer of the diagram and insert the data that the wrapper
| id | id of the shape |
| type | if set to group then this node indicates *a cluster*. |
| padding | Padding. Passed from the render as this might differ between different diagrams. Maybe obsolete. |
| data | Non-generic data specific to the shape. |
# edge
@ -112,6 +113,8 @@ Required edgeData for proper rendering:
| label | overlap between label and labelText? |
| labelPos | |
| labelType | overlap between label and labelText? |
| thickness | Sets the thinkess of the edge. Can be \['normal', 'thick'\] |
| pattern | Sets the pattern of the edge. Can be \['solid', 'dotted', 'dashed'\] |
# Markers
@ -119,7 +122,7 @@ Required edgeData for proper rendering:
Define what markers that should be included in the diagram with the insert markers function. The function takes two arguments, first the element in which the markers should be included and a list of the markers that should be added.
Ex:
insertMarkers(el, ['point', 'circle'])
insertMarkers(el, \['point', 'circle'\])
The example above adds the markers point and cross. This means that edges with the arrowTypes arrow_cross, double_arrow_cross, arrow_point and double_arrow_cross will get the corresponding markers but arrowType arrow_cross will have no impact.
@ -133,4 +136,4 @@ Current markers:
# Common functions used by the renderer to be implemented by the Db
getDirection
getClasses
getClasses

View File

@ -2,6 +2,8 @@ import { logger } from '../logger'; // eslint-disable-line
import createLabel from './createLabel';
import { line, curveBasis, select } from 'd3';
import { getConfig } from '../config';
import utils from '../utils';
// import { calcLabelPosition } from '../utils';
let edgeLabels = {};
@ -39,11 +41,19 @@ export const insertEdgeLabel = (elem, edge) => {
edge.height = bbox.height;
};
export const positionEdgeLabel = edge => {
export const positionEdgeLabel = (edge, points) => {
logger.info('Moving label', edge.id, edge.label, edgeLabels[edge.id]);
if (edge.label) {
const el = edgeLabels[edge.id];
el.attr('transform', 'translate(' + edge.x + ', ' + edge.y + ')');
let x = edge.x;
let y = edge.y;
if (points) {
// debugger;
const pos = utils.calcLabelPosition(points);
x = pos.x;
y = pos.y;
}
el.attr('transform', 'translate(' + x + ', ' + y + ')');
}
};
@ -61,47 +71,80 @@ export const positionEdgeLabel = edge => {
// };
const outsideNode = (node, point) => {
// logger.warn('Checking bounds ', node, point);
const x = node.x;
const y = node.y;
const dx = Math.abs(point.x - x);
const dy = Math.abs(point.y - y);
const w = node.width / 2;
const h = node.height / 2;
if (dx > w || dy > h) {
if (dx >= w || dy >= h) {
return true;
}
return false;
};
const intersection = (node, outsidePoint, insidePoint) => {
logger.trace('intersection o:', outsidePoint, ' i:', insidePoint, node);
export const intersection = (node, outsidePoint, insidePoint) => {
logger.warn('intersection calc o:', outsidePoint, ' i:', insidePoint, node);
const x = node.x;
const y = node.y;
const dx = Math.abs(x - insidePoint.x);
const w = node.width / 2;
let r = insidePoint.x < outsidePoint.x ? w - dx : w + dx;
const dy = Math.abs(y - insidePoint.y);
const h = node.height / 2;
let q = insidePoint.y < outsidePoint.y ? h - dy : h - dy;
const edges = {
x1: x - w,
x2: x + w,
y1: y - h,
y2: y + h
};
if (
outsidePoint.x === edges.x1 ||
outsidePoint.x === edges.x2 ||
outsidePoint.y === edges.y1 ||
outsidePoint.y === edges.y2
) {
logger.warn('calc equals on edge');
return outsidePoint;
}
const Q = Math.abs(outsidePoint.y - insidePoint.y);
const R = Math.abs(outsidePoint.x - insidePoint.x);
if (Math.abs(y - outsidePoint.y) * w > Math.abs(x - outsidePoint.x) * h || false) { // eslint-disable-line
// log.warn();
if (Math.abs(y - outsidePoint.y) * w > Math.abs(x - outsidePoint.x) * h) { // eslint-disable-line
// Intersection is top or bottom of rect.
// let q = insidePoint.y < outsidePoint.y ? outsidePoint.y - h - y : y - h - outsidePoint.y;
let q = insidePoint.y < outsidePoint.y ? outsidePoint.y - h - y : y - h - outsidePoint.y;
r = (R * q) / Q;
return {
x: insidePoint.x < outsidePoint.x ? insidePoint.x + r : insidePoint.x - r,
y: insidePoint.y + q
const res = {
x: insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : insidePoint.x - r,
y: outsidePoint.y + q
};
logger.warn(`topp/bott calc, Q ${Q}, q ${q}, R ${R}, r ${r}`, res);
return res;
} else {
q = (Q * r) / R;
r = (R * q) / Q;
// Intersection onn sides of rect
// q = (Q * r) / R;
// q = 2;
// r = (R * q) / Q;
if (insidePoint.x < outsidePoint.x) {
r = outsidePoint.x - w - x;
} else {
// r = outsidePoint.x - w - x;
r = x - w - outsidePoint.x;
}
let q = (q = (Q * r) / R);
logger.warn(`sides calc, Q ${Q}, q ${q}, R ${R}, r ${r}`, {
x: insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : insidePoint.x + dx - w,
y: insidePoint.y < outsidePoint.y ? insidePoint.y + q : insidePoint.y - q
});
return {
x: insidePoint.x < outsidePoint.x ? insidePoint.x + r : insidePoint.x + dx - w,
x: insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : insidePoint.x + dx - w,
y: insidePoint.y < outsidePoint.y ? insidePoint.y + q : insidePoint.y - q
};
}
@ -110,7 +153,7 @@ const intersection = (node, outsidePoint, insidePoint) => {
//(edgePaths, e, edge, clusterDb, diagramtype, graph)
export const insertEdge = function(elem, e, edge, clusterDb, diagramType, graph) {
let points = edge.points;
let pointsHasChanged = false;
const tail = graph.node(e.v);
var head = graph.node(e.w);
@ -138,20 +181,30 @@ export const insertEdge = function(elem, e, edge, clusterDb, diagramType, graph)
logger.trace('inside', edge.toCluster, point, lastPointOutside);
// First point inside the rect
const insterection = intersection(node, lastPointOutside, point);
logger.trace('intersect', insterection);
points.push(insterection);
const inter = intersection(node, lastPointOutside, point);
let pointPresent = false;
points.forEach(p => {
pointPresent = pointPresent || (p.x === inter.x && p.y === inter.y);
});
// if (!pointPresent) {
if (!points.find(e => e.x === inter.x && e.y === inter.y)) {
points.push(inter);
} else {
logger.warn('no intersect', inter, points);
}
isInside = true;
} else {
if (!isInside) points.push(point);
}
lastPointOutside = point;
});
pointsHasChanged = true;
}
if (edge.fromCluster) {
logger.trace('edge', edge);
logger.trace('from cluster', clusterDb[edge.toCluster]);
logger.warn('from cluster', clusterDb[edge.fromCluster]);
const updatedPoints = [];
let lastPointOutside;
let isInside = false;
@ -160,7 +213,7 @@ export const insertEdge = function(elem, e, edge, clusterDb, diagramType, graph)
const node = clusterDb[edge.fromCluster].node;
if (!outsideNode(node, point) && !isInside) {
logger.trace('inside', edge.toCluster, point);
logger.warn('inside', edge.fromCluster, point, node);
// First point inside the rect
const insterection = intersection(node, lastPointOutside, point);
@ -176,6 +229,7 @@ export const insertEdge = function(elem, e, edge, clusterDb, diagramType, graph)
lastPointOutside = point;
}
points = updatedPoints;
pointsHasChanged = true;
}
// The data for our line
@ -191,11 +245,35 @@ export const insertEdge = function(elem, e, edge, clusterDb, diagramType, graph)
})
.curve(curveBasis);
// Contruct stroke classes based on properties
let strokeClasses;
switch (edge.thickness) {
case 'normal':
strokeClasses = 'edge-thickness-normal';
break;
case 'thick':
strokeClasses = 'edge-thickness-thick';
break;
default:
strokeClasses = '';
}
switch (edge.pattern) {
case 'solid':
strokeClasses += ' edge-pattern-solid';
break;
case 'dotted':
strokeClasses += ' edge-pattern-dotted';
break;
case 'dashed':
strokeClasses += ' edge-pattern-dashed';
break;
}
const svgPath = elem
.append('path')
.attr('d', lineFunction(lineData))
.attr('id', edge.id)
.attr('class', 'transition' + (edge.classes ? ' ' + edge.classes : ''));
.attr('class', ' ' + strokeClasses + (edge.classes ? ' ' + edge.classes : ''));
// DEBUG code, adds a red circle at each edge coordinate
// edge.points.forEach(point => {
@ -219,36 +297,65 @@ export const insertEdge = function(elem, e, edge, clusterDb, diagramType, graph)
url = url.replace(/\(/g, '\\(');
url = url.replace(/\)/g, '\\)');
}
logger.info('arrowType', edge.arrowType);
switch (edge.arrowType) {
logger.info('arrowTypeStart', edge.arrowTypeStart);
logger.info('arrowTypeEnd', edge.arrowTypeEnd);
switch (edge.arrowTypeStart) {
case 'arrow_cross':
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-crossStart' + ')');
break;
case 'arrow_point':
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-pointStart' + ')');
break;
case 'arrow_barb':
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-barbStart' + ')');
break;
case 'arrow_circle':
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-circleStart' + ')');
break;
case 'aggregation':
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-aggregationStart' + ')');
break;
case 'extension':
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-extensionStart' + ')');
break;
case 'composition':
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-compositionStart' + ')');
break;
case 'dependency':
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-dependencyStart' + ')');
break;
default:
}
switch (edge.arrowTypeEnd) {
case 'arrow_cross':
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-crossEnd' + ')');
break;
case 'double_arrow_cross':
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-crossEnd' + ')');
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-crossStart' + ')');
break;
case 'arrow_point':
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-pointEnd' + ')');
break;
case 'double_arrow_point':
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-pointEnd' + ')');
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-pointStart' + ')');
break;
case 'arrow_barb':
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-barbEnd' + ')');
break;
case 'double_arrow_barb':
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-barnEnd' + ')');
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-barbStart' + ')');
break;
case 'arrow_circle':
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-circleEnd' + ')');
break;
case 'double_arrow_circle':
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-circleEnd' + ')');
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-circleStart' + ')');
case 'aggregation':
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-aggregationEnd' + ')');
break;
case 'extension':
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-extensionEnd' + ')');
break;
case 'composition':
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-compositionEnd' + ')');
break;
case 'dependency':
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-dependencyEnd' + ')');
break;
default:
}
if (pointsHasChanged) {
return points;
}
};

View File

@ -0,0 +1,63 @@
import { intersection } from './edges';
import { setLogLevel, logger } from '../logger';
describe('Graphlib decorations', () => {
let node;
beforeEach(function () {
setLogLevel(1);
node = { x:171, y:100, width: 210, height: 184};
});
describe('intersection', function () {
it('case 1 - intersection on left edge of box', function () {
const o = {x: 31, y: 143.2257070163421};
const i = {x: 99.3359375, y: 100}
const int = intersection(node, o, i);
expect(int.x).toBe(66)
expect(int.y).toBeCloseTo(122.139)
});
it('case 2 - intersection on left edge of box', function () {
const o = {x: 310.2578125, y: 169.88002060631462};
const i = {x: 127.96875, y: 100};
const node2 = {
height: 337.5,
width: 184.4609375,
x: 100.23046875,
y: 176.75
}
const int = intersection(node2, o, i);
expect(int.x).toBeCloseTo(192.4609375)
expect(int.y).toBeCloseTo(145.15711441743503)
});
it('case 3 - intersection on otop of box outside point greater then inside point', function () {
const o = {x: 157.21875, y: 38.83361558001693};
const i = {x: 104.1328125, y: 105};
const node2 = {
width: 211.96875,
x: 113.984375,
y: 164.25,
height: 176.5
}
const int = intersection(node2, o, i);
expect(int.x).toBeCloseTo(127.39979619565217)
expect(int.y).toBeCloseTo(76)
});
it('case 4 - intersection on top of box inside point greater then inside point', function () {
const o = {x: 144.65625, y: 38.83361558001693};
const i = {x: 197.7421875, y: 105};
const node2 = {
width: 211.96875,
x: 113.984375,
y: 164.25,
height: 176.5
}
const int = intersection(node2, o, i);
expect(int.x).toBeCloseTo(167.9232336956522)
expect(int.y).toBeCloseTo(76)
});
});
});

View File

@ -20,12 +20,12 @@ const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
const elem = _elem.insert('g').attr('class', 'root'); // eslint-disable-line
if (!graph.nodes()) {
log.trace('No nodes found for', graph);
log.info('No nodes found for', graph);
} else {
log.trace('Recursive render', graph.nodes());
log.info('Recursive render', graph.nodes());
}
if (graph.edges().length > 0) {
log.trace('Recursive edges', graph.edge(graph.edges()[0]));
log.info('Recursive edges', graph.edge(graph.edges()[0]));
}
const clusters = elem.insert('g').attr('class', 'clusters'); // eslint-disable-line
const edgePaths = elem.insert('g').attr('class', 'edgePaths');
@ -39,14 +39,14 @@ const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
if (typeof parentCluster !== 'undefined') {
const data = JSON.parse(JSON.stringify(parentCluster.clusterData));
// data.clusterPositioning = true;
log.trace('Setting data for cluster', data);
log.info('Setting data for cluster', data);
graph.setNode(parentCluster.id, data);
graph.setParent(v, parentCluster.id, data);
}
log.trace('(Insert) Node ' + v + ': ' + JSON.stringify(graph.node(v)));
log.info('(Insert) Node ' + v + ': ' + JSON.stringify(graph.node(v)));
if (node && node.clusterNode) {
// const children = graph.children(v);
log.trace('Cluster identified', v, node, graph.node(v));
log.info('Cluster identified', v, node, graph.node(v));
const newEl = recursiveRender(nodes, node.graph, diagramtype, graph.node(v));
updateNodeBounds(node, newEl);
setNodeElem(newEl, node);
@ -56,12 +56,12 @@ const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
if (graph.children(v).length > 0) {
// This is a cluster but not to be rendered recusively
// Render as before
log.trace('Cluster - the non recursive path', v, node.id, node, graph);
log.trace(findNonClusterChild(node.id, graph));
log.info('Cluster - the non recursive path', v, node.id, node, graph);
log.info(findNonClusterChild(node.id, graph));
clusterDb[node.id] = { id: findNonClusterChild(node.id, graph), node };
// insertCluster(clusters, graph.node(v));
} else {
log.trace('Node - the non recursive path', v, node.id, node);
log.info('Node - the non recursive path', v, node.id, node);
insertNode(nodes, graph.node(v), dir);
}
}
@ -73,11 +73,11 @@ const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
// TODO: pick optimal child in the cluster to us as link anchor
graph.edges().forEach(function(e) {
const edge = graph.edge(e.v, e.w, e.name);
log.trace('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(e));
log.trace('Edge ' + e.v + ' -> ' + e.w + ': ', e, ' ', JSON.stringify(graph.edge(e)));
log.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(e));
log.info('Edge ' + e.v + ' -> ' + e.w + ': ', e, ' ', JSON.stringify(graph.edge(e)));
// Check if link is either from or to a cluster
log.trace('Fix', clusterDb, 'ids:', e.v, e.w, 'Translateing: ', clusterDb[e.v], clusterDb[e.w]);
log.info('Fix', clusterDb, 'ids:', e.v, e.w, 'Translateing: ', clusterDb[e.v], clusterDb[e.w]);
insertEdgeLabel(edgeLabels, edge);
});
@ -89,11 +89,11 @@ const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
log.info('#############################################');
log.info(graph);
dagre.layout(graph);
log.trace('Graph after layout:', graphlib.json.write(graph));
log.info('Graph after layout:', graphlib.json.write(graph));
// Move the nodes to the correct place
graph.nodes().forEach(function(v) {
const node = graph.node(v);
log.trace('Position ' + v + ': ' + JSON.stringify(graph.node(v)));
log.info('Position ' + v + ': ' + JSON.stringify(graph.node(v)));
log.info(
'Position ' + v + ': (' + node.x,
',' + node.y,
@ -124,8 +124,8 @@ const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
const edge = graph.edge(e);
log.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(edge), edge);
insertEdge(edgePaths, e, edge, clusterDb, diagramtype, graph);
positionEdgeLabel(edge);
const updatedPath = insertEdge(edgePaths, e, edge, clusterDb, diagramtype, graph);
positionEdgeLabel(edge, updatedPath);
});
return elem;

View File

@ -16,10 +16,15 @@ function intersectPolygon(node, polyPoints, point) {
var minX = Number.POSITIVE_INFINITY;
var minY = Number.POSITIVE_INFINITY;
polyPoints.forEach(function(entry) {
minX = Math.min(minX, entry.x);
minY = Math.min(minY, entry.y);
});
if (typeof polyPoints.forEach === 'function') {
polyPoints.forEach(function(entry) {
minX = Math.min(minX, entry.x);
minY = Math.min(minY, entry.y);
});
} else {
minX = Math.min(minX, polyPoints.x);
minY = Math.min(minY, polyPoints.y);
}
var left = x1 - node.width / 2 - minX;
var top = y1 - node.height / 2 - minY;

View File

@ -17,7 +17,7 @@ const extension = (elem, type, id) => {
.append('defs')
.append('marker')
.attr('id', type + '-extensionStart')
.attr('class', 'extension ' + type)
.attr('class', 'marker extension ' + type)
.attr('refX', 0)
.attr('refY', 7)
.attr('markerWidth', 190)
@ -29,8 +29,8 @@ const extension = (elem, type, id) => {
elem
.append('defs')
.append('marker')
.attr('id', type + '-extensionEnd ' + type)
.attr('class', 'extension ' + type)
.attr('id', type + '-extensionEnd')
.attr('class', 'marker extension ' + type)
.attr('refX', 19)
.attr('refY', 7)
.attr('markerWidth', 20)
@ -45,7 +45,7 @@ const composition = (elem, type) => {
.append('defs')
.append('marker')
.attr('id', type + '-compositionStart')
.attr('class', 'extension ' + type)
.attr('class', 'marker composition ' + type)
.attr('refX', 0)
.attr('refY', 7)
.attr('markerWidth', 190)
@ -58,7 +58,7 @@ const composition = (elem, type) => {
.append('defs')
.append('marker')
.attr('id', type + '-compositionEnd')
.attr('class', 'extension ' + type)
.attr('class', 'marker composition ' + type)
.attr('refX', 19)
.attr('refY', 7)
.attr('markerWidth', 20)
@ -72,7 +72,7 @@ const aggregation = (elem, type) => {
.append('defs')
.append('marker')
.attr('id', type + '-aggregationStart')
.attr('class', 'extension ' + type)
.attr('class', 'marker aggregation ' + type)
.attr('refX', 0)
.attr('refY', 7)
.attr('markerWidth', 190)
@ -85,7 +85,7 @@ const aggregation = (elem, type) => {
.append('defs')
.append('marker')
.attr('id', type + '-aggregationEnd')
.attr('class', type)
.attr('class', 'marker aggregation ' + type)
.attr('refX', 19)
.attr('refY', 7)
.attr('markerWidth', 20)
@ -99,7 +99,7 @@ const dependency = (elem, type) => {
.append('defs')
.append('marker')
.attr('id', type + '-dependencyStart')
.attr('class', 'extension ' + type)
.attr('class', 'marker dependency ' + type)
.attr('refX', 0)
.attr('refY', 7)
.attr('markerWidth', 190)
@ -112,7 +112,7 @@ const dependency = (elem, type) => {
.append('defs')
.append('marker')
.attr('id', type + '-dependencyEnd')
.attr('class', type)
.attr('class', 'marker dependency ' + type)
.attr('refX', 19)
.attr('refY', 7)
.attr('markerWidth', 20)
@ -125,13 +125,13 @@ const point = (elem, type) => {
elem
.append('marker')
.attr('id', type + '-pointEnd')
.attr('class', type)
.attr('class', 'marker ' + type)
.attr('viewBox', '0 0 10 10')
.attr('refX', 10)
.attr('refX', 9)
.attr('refY', 5)
.attr('markerUnits', 'strokeWidth')
.attr('markerWidth', 8)
.attr('markerHeight', 8)
.attr('markerUnits', 'userSpaceOnUse')
.attr('markerWidth', 12)
.attr('markerHeight', 12)
.attr('orient', 'auto')
.append('path')
.attr('d', 'M 0 0 L 10 5 L 0 10 z')
@ -141,13 +141,13 @@ const point = (elem, type) => {
elem
.append('marker')
.attr('id', type + '-pointStart')
.attr('class', type)
.attr('class', 'marker ' + type)
.attr('viewBox', '0 0 10 10')
.attr('refX', 0)
.attr('refY', 5)
.attr('markerUnits', 'strokeWidth')
.attr('markerWidth', 8)
.attr('markerHeight', 8)
.attr('markerUnits', 'userSpaceOnUse')
.attr('markerWidth', 12)
.attr('markerHeight', 12)
.attr('orient', 'auto')
.append('path')
.attr('d', 'M 0 5 L 10 10 L 10 0 z')
@ -159,13 +159,13 @@ const circle = (elem, type) => {
elem
.append('marker')
.attr('id', type + '-circleEnd')
.attr('class', type)
.attr('class', 'marker ' + type)
.attr('viewBox', '0 0 10 10')
.attr('refX', 11)
.attr('refY', 5)
.attr('markerUnits', 'strokeWidth')
.attr('markerWidth', 7)
.attr('markerHeight', 7)
.attr('markerUnits', 'userSpaceOnUse')
.attr('markerWidth', 11)
.attr('markerHeight', 11)
.attr('orient', 'auto')
.append('circle')
.attr('cx', '5')
@ -178,13 +178,13 @@ const circle = (elem, type) => {
elem
.append('marker')
.attr('id', type + '-circleStart')
.attr('class', type)
.attr('class', 'marker ' + type)
.attr('viewBox', '0 0 10 10')
.attr('refX', -1)
.attr('refY', 5)
.attr('markerUnits', 'strokeWidth')
.attr('markerWidth', 7)
.attr('markerHeight', 7)
.attr('markerUnits', 'userSpaceOnUse')
.attr('markerWidth', 11)
.attr('markerHeight', 11)
.attr('orient', 'auto')
.append('circle')
.attr('cx', '5')
@ -198,16 +198,16 @@ const cross = (elem, type) => {
elem
.append('marker')
.attr('id', type + '-crossEnd')
.attr('class', type)
.attr('class', 'marker cross ' + type)
.attr('viewBox', '0 0 11 11')
.attr('refX', 12)
.attr('refY', 5.2)
.attr('markerUnits', 'strokeWidth')
.attr('markerWidth', 7)
.attr('markerHeight', 7)
.attr('markerUnits', 'userSpaceOnUse')
.attr('markerWidth', 11)
.attr('markerHeight', 11)
.attr('orient', 'auto')
.append('path')
.attr('stroke', 'black')
// .attr('stroke', 'black')
.attr('d', 'M 1,1 l 9,9 M 10,1 l -9,9')
.attr('class', 'arrowMarkerPath')
.style('stroke-width', 2)
@ -216,16 +216,16 @@ const cross = (elem, type) => {
elem
.append('marker')
.attr('id', type + '-crossStart')
.attr('class', type)
.attr('class', 'marker cross ' + type)
.attr('viewBox', '0 0 11 11')
.attr('refX', -1)
.attr('refY', 5.2)
.attr('markerUnits', 'strokeWidth')
.attr('markerWidth', 7)
.attr('markerHeight', 7)
.attr('markerUnits', 'userSpaceOnUse')
.attr('markerWidth', 11)
.attr('markerHeight', 11)
.attr('orient', 'auto')
.append('path')
.attr('stroke', 'black')
// .attr('stroke', 'black')
.attr('d', 'M 1,1 l 9,9 M 10,1 l -9,9')
.attr('class', 'arrowMarkerPath')
.style('stroke-width', 2)
@ -240,7 +240,7 @@ const barb = (elem, type) => {
.attr('refY', 7)
.attr('markerWidth', 20)
.attr('markerHeight', 14)
.attr('markerUnits', 0)
.attr('markerUnits', 'strokeWidth')
.attr('orient', 'auto')
.append('path')
.attr('d', 'M 19,7 L9,13 L14,7 L9,1 Z');

View File

@ -171,7 +171,9 @@ export const validate = graph => {
export const findNonClusterChild = (id, graph) => {
// const node = graph.node(id);
log.trace('Searching', id);
const children = graph.children(id);
// const children = graph.children(id).reverse();
const children = graph.children(id); //.reverse();
log.trace('Searching children of id ', id, children);
if (children.length < 1) {
log.trace('This is a valid node', id);
return id;
@ -213,7 +215,7 @@ export const adjustClustersAndEdges = (graph, depth) => {
graph.nodes().forEach(function(id) {
const children = graph.children(id);
if (children.length > 0) {
log.trace(
log.warn(
'Cluster identified',
id,
' Replacement id in edges: ',
@ -266,17 +268,17 @@ export const adjustClustersAndEdges = (graph, depth) => {
// Check if link is either from or to a cluster
log.trace('Fix', clusterDb, 'ids:', e.v, e.w, 'Translateing: ', clusterDb[e.v], clusterDb[e.w]);
if (clusterDb[e.v] || clusterDb[e.w]) {
log.trace('Fixing and trixing - removing', e.v, e.w, e.name);
log.warn('Fixing and trixing - removing', e.v, e.w, e.name);
v = getAnchorId(e.v);
w = getAnchorId(e.w);
graph.removeEdge(e.v, e.w, e.name);
if (v !== e.v) edge.fromCluster = e.v;
if (w !== e.w) edge.toCluster = e.w;
log.trace('Replacing with', v, w, e.name);
log.warn('Replacing with', v, w, e.name);
graph.setEdge(v, w, edge, e.name);
}
});
log.debug('Adjusted Graph', graphlib.json.write(graph));
log.warn('Adjusted Graph', graphlib.json.write(graph));
log.trace(clusterDb);

View File

@ -1,8 +1,8 @@
import intersect from './intersect/index.js';
import { select } from 'd3';
import { logger } from '../logger'; // eslint-disable-line
import { labelHelper, updateNodeBounds, insertPolygonShape } from './shapes/util';
import { getConfig } from '../config';
import intersect from './intersect/index.js';
import createLabel from './createLabel';
import note from './shapes/note';
@ -539,6 +539,219 @@ const end = (parent, node) => {
return shapeSvg;
};
const class_box = (parent, node) => {
const halfPadding = node.padding / 2;
const rowPadding = 4;
const lineHeight = 8;
let classes;
if (!node.classes) {
classes = 'node default';
} else {
classes = 'node ' + node.classes;
}
// Add outer g element
const shapeSvg = parent
.insert('g')
.attr('class', classes)
.attr('id', node.id);
// Create the title label and insert it after the rect
const rect = shapeSvg.insert('rect', ':first-child');
const topLine = shapeSvg.insert('line');
const bottomLine = shapeSvg.insert('line');
let maxWidth = 0;
let maxHeight = rowPadding;
const labelContainer = shapeSvg.insert('g').attr('class', 'label');
let verticalPos = 0;
const hasInterface = node.classData.annotations && node.classData.annotations[0];
// 1. Create the labels
const interfaceLabel = labelContainer
.node()
.appendChild(createLabel(node.classData.annotations[0], node.labelStyle, true, true));
const interfaceBBox = interfaceLabel.getBBox();
if (node.classData.annotations[0]) {
maxHeight += interfaceBBox.height + rowPadding;
maxWidth += interfaceBBox.width;
}
const classTitleLabel = labelContainer
.node()
.appendChild(createLabel(node.labelText, node.labelStyle, true, true));
const classTitleBBox = classTitleLabel.getBBox();
maxHeight += classTitleBBox.height + rowPadding;
if (classTitleBBox.width > maxWidth) {
maxWidth = classTitleBBox.width;
}
const classAttributes = [];
node.classData.members.forEach(str => {
const lbl = labelContainer.node().appendChild(createLabel(str, node.labelStyle, true, true));
const bbox = lbl.getBBox();
if (bbox.width > maxWidth) {
maxWidth = bbox.width;
}
maxHeight += bbox.height + rowPadding;
classAttributes.push(lbl);
});
const classMethods = [];
node.classData.methods.forEach(str => {
const lbl = labelContainer.node().appendChild(createLabel(str, node.labelStyle, true, true));
const bbox = lbl.getBBox();
if (bbox.width > maxWidth) {
maxWidth = bbox.width;
}
maxHeight += bbox.height + rowPadding;
classMethods.push(lbl);
});
maxHeight += lineHeight;
// 2. Position the labels
// position the interface label
if (hasInterface) {
select(interfaceLabel).attr(
'transform',
'translate( ' +
-(maxWidth + node.padding - interfaceBBox.width / 2) / 2 +
', ' +
(-1 * maxHeight) / 2 +
')'
);
verticalPos = interfaceBBox.height + rowPadding;
}
// Positin the class title label
let diffX = (maxWidth - classTitleBBox.width) / 2;
select(classTitleLabel).attr(
'transform',
'translate( ' +
((-1 * maxWidth) / 2 + diffX) +
', ' +
((-1 * maxHeight) / 2 + verticalPos) +
')'
);
verticalPos += classTitleBBox.height + rowPadding;
topLine
.attr('class', 'divider')
.attr('x1', -maxWidth / 2 - halfPadding)
.attr('x2', maxWidth / 2 + halfPadding)
.attr('y1', -maxHeight / 2 - halfPadding + lineHeight + verticalPos)
.attr('y2', -maxHeight / 2 - halfPadding + lineHeight + verticalPos);
verticalPos += lineHeight;
classAttributes.forEach(lbl => {
select(lbl).attr(
'transform',
'translate( ' +
-maxWidth / 2 +
', ' +
((-1 * maxHeight) / 2 + verticalPos + lineHeight / 2) +
')'
);
verticalPos += classTitleBBox.height + rowPadding;
});
bottomLine
.attr('class', 'divider')
.attr('x1', -maxWidth / 2 - halfPadding)
.attr('x2', maxWidth / 2 + halfPadding)
.attr('y1', -maxHeight / 2 - halfPadding + lineHeight + verticalPos)
.attr('y2', -maxHeight / 2 - halfPadding + lineHeight + verticalPos);
verticalPos += lineHeight;
classMethods.forEach(lbl => {
select(lbl).attr(
'transform',
'translate( ' + -maxWidth / 2 + ', ' + ((-1 * maxHeight) / 2 + verticalPos) + ')'
);
verticalPos += classTitleBBox.height + rowPadding;
});
//
let bbox;
if (getConfig().flowchart.htmlLabels) {
const div = interfaceLabel.children[0];
const dv = select(interfaceLabel);
bbox = div.getBoundingClientRect();
dv.attr('width', bbox.width);
dv.attr('height', bbox.height);
}
// bbox = labelContainer.getBBox();
// logger.info('Text 2', text2);
// const textRows = text2.slice(1, text2.length);
// let titleBox = text.getBBox();
// const descr = label
// .node()
// .appendChild(createLabel(textRows.join('<br/>'), node.labelStyle, true, true));
// if (getConfig().flowchart.htmlLabels) {
// const div = descr.children[0];
// const dv = select(descr);
// bbox = div.getBoundingClientRect();
// dv.attr('width', bbox.width);
// dv.attr('height', bbox.height);
// }
// // bbox = label.getBBox();
// // logger.info(descr);
// select(descr).attr(
// 'transform',
// 'translate( ' +
// // (titleBox.width - bbox.width) / 2 +
// (bbox.width > titleBox.width ? 0 : (titleBox.width - bbox.width) / 2) +
// ', ' +
// (titleBox.height + halfPadding + 5) +
// ')'
// );
// select(text).attr(
// 'transform',
// 'translate( ' +
// // (titleBox.width - bbox.width) / 2 +
// (bbox.width < titleBox.width ? 0 : -(titleBox.width - bbox.width) / 2) +
// ', ' +
// 0 +
// ')'
// );
// // Get the size of the label
// // Bounding box for title and text
// bbox = label.node().getBBox();
// // Center the label
// label.attr(
// 'transform',
// 'translate(' + -bbox.width / 2 + ', ' + (-bbox.height / 2 - halfPadding + 3) + ')'
// );
rect
.attr('class', 'outer title-state')
.attr('x', -maxWidth / 2 - halfPadding)
.attr('y', -(maxHeight / 2) - halfPadding)
.attr('width', maxWidth + node.padding)
.attr('height', maxHeight + node.padding);
// innerLine
// .attr('class', 'divider')
// .attr('x1', -bbox.width / 2 - halfPadding)
// .attr('x2', bbox.width / 2 + halfPadding)
// .attr('y1', -bbox.height / 2 - halfPadding + titleBox.height + halfPadding)
// .attr('y2', -bbox.height / 2 - halfPadding + titleBox.height + halfPadding);
updateNodeBounds(node, rect);
node.intersect = function(point) {
return intersect.rect(node, point);
};
return shapeSvg;
};
const shapes = {
question,
rect,
@ -558,7 +771,8 @@ const shapes = {
note,
subroutine,
fork: forkJoin,
join: forkJoin
join: forkJoin,
class_box
};
let nodeElems = {};

View File

@ -1,8 +1,9 @@
import { select } from 'd3';
import { logger } from '../../logger';
import { getConfig } from '../../config';
import configApi, { getConfig } from '../../config';
import common from '../common/common';
import utils from '../../utils';
import mermaidAPI from '../../mermaidAPI';
const MERMAID_DOM_ID_PREFIX = 'classid-';
@ -14,6 +15,10 @@ let classCounter = 0;
let funs = [];
export const parseDirective = function(statement, context, type) {
mermaidAPI.parseDirective(this, statement, context, type);
};
const splitClassNameAndType = function(id) {
let genericType = '';
let className = id;
@ -217,7 +222,7 @@ const setClickFunc = function(domId, functionName, tooltip) {
elem.addEventListener(
'click',
function() {
window[functionName](elemId);
utils.runFunc(functionName, elemId);
},
false
);
@ -272,8 +277,8 @@ const setupToolTips = function(element) {
.style('opacity', '.9');
tooltipElem
.html(el.attr('title'))
.style('left', rect.left + (rect.right - rect.left) / 2 + 'px')
.style('top', rect.top - 14 + document.body.scrollTop + 'px');
.style('left', window.scrollX + rect.left + (rect.right - rect.left) / 2 + 'px')
.style('top', window.scrollY + rect.top - 14 + document.body.scrollTop + 'px');
el.classed('hover', true);
})
.on('mouseout', function() {
@ -288,6 +293,8 @@ const setupToolTips = function(element) {
funs.push(setupToolTips);
export default {
parseDirective,
getConfig: () => configApi.getConfig().class,
addClass,
bindFunctions,
clear,

View File

@ -242,69 +242,74 @@ describe('class diagram, ', function () {
it('should handle comments at the start', function () {
const str =
'%% Comment\n' +
'classDiagram\n' +
'class Class1 {\n' +
'int : test\n' +
'string : foo\n' +
'test()\n' +
'foo()\n' +
'}';
`%% Comment
classDiagram
class Class1 {
int : test
string : foo
test()
foo()
}`;
parser.parse(str);
});
it('should handle comments at the end', function () {
const str =
'classDiagram\n' +
'class Class1 {\n' +
'int : test\n' +
'string : foo\n' +
'test()\n' +
'foo()\n' +
'\n}' +
'%% Comment\n';
`classDiagram
class Class1 {
int : test
string : foo
test()
foo()
}
%% Comment
`;
parser.parse(str);
});
it('should handle comments at the end no trailing newline', function () {
const str =
'classDiagram\n' +
'class Class1 {\n' +
'int : test\n' +
'string : foo\n' +
'test()\n' +
'foo()\n' +
'}\n' +
'%% Comment';
`classDiagram
class Class1 {
int : test
string : foo
test()
foo()
}
%% Comment`;
parser.parse(str);
});
it('should handle a comment with multiple line feeds', function () {
const str =
'classDiagram\n\n\n' +
'%% Comment\n\n' +
'class Class1 {\n' +
'int : test\n' +
'string : foo\n' +
'test()\n' +
'foo()\n' +
'}';
`classDiagram
%% Comment
class Class1 {
int : test
string : foo
test()
foo()
}`;
parser.parse(str);
});
it('should handle a comment with mermaid class diagram code in them', function () {
const str =
'classDiagram\n' +
'%% Comment Class01 <|-- Class02\n' +
'class Class1 {\n' +
'int : test\n' +
'string : foo\n' +
'test()\n' +
'foo()\n' +
'}';
`classDiagram
%% Comment Class01 <|-- Class02
class Class1 {
int : test
string : foo
test()
foo()
}`;
parser.parse(str);
});
@ -640,7 +645,7 @@ describe('class diagram, ', function () {
expect(testClass.cssClasses.length).toBe(1);
expect(testClass.cssClasses[0]).toBe('clickable');
});
it('should associate link with tooltip', function () {
const str = 'classDiagram\n' + 'class Class1\n' + 'Class1 : someMethod()\n' + 'link Class1 "google.com" "A tooltip"';
parser.parse(str);

View File

@ -0,0 +1,523 @@
import { select } from 'd3';
import dagre from 'dagre';
import graphlib from 'graphlib';
import { logger } from '../../logger';
import classDb, { lookUpDomId } from './classDb';
import { parser } from './parser/classDiagram';
import svgDraw from './svgDraw';
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 } from '../../utils';
import common from '../common/common';
parser.yy = classDb;
let idCache = {};
const padding = 20;
const conf = {
dividerMargin: 10,
padding: 5,
textHeight: 10
};
/**
* Function that adds the vertices found during parsing to the graph to be rendered.
* @param vert Object containing the vertices.
* @param g The graph that is to be drawn.
*/
export const addClasses = function(classes, g) {
// const svg = select(`[id="${svgId}"]`);
const keys = Object.keys(classes);
logger.info('keys:', keys);
logger.info(classes);
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
keys.forEach(function(id) {
const vertex = classes[id];
/**
* Variable for storing the classes for the vertex
* @type {string}
*/
let classStr = 'default';
// if (vertex.classes.length > 0) {
// classStr = vertex.classes.join(' ');
// }
const styles = { labelStyle: '' }; //getStylesFromArray(vertex.styles);
// Use vertex id as text in the box if no text is provided by the graph definition
let vertexText = vertex.text !== undefined ? vertex.text : vertex.id;
// We create a SVG label, either by delegating to addHtmlLabel or manually
// let vertexNode;
// if (getConfig().flowchart.htmlLabels) {
// const node = {
// label: vertexText.replace(
// /fa[lrsb]?:fa-[\w-]+/g,
// s => `<i class='${s.replace(':', ' ')}'></i>`
// )
// };
// vertexNode = addHtmlLabel(svg, node).node();
// vertexNode.parentNode.removeChild(vertexNode);
// } else {
// const svgLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text');
// svgLabel.setAttribute('style', styles.labelStyle.replace('color:', 'fill:'));
// const rows = vertexText.split(common.lineBreakRegex);
// for (let j = 0; j < rows.length; j++) {
// const tspan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
// tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
// tspan.setAttribute('dy', '1em');
// tspan.setAttribute('x', '1');
// tspan.textContent = rows[j];
// svgLabel.appendChild(tspan);
// }
// vertexNode = svgLabel;
// }
let radious = 0;
let _shape = '';
// Set the shape based parameters
switch (vertex.type) {
case 'class':
_shape = 'class_box';
break;
default:
_shape = 'class_box';
}
// Add the node
g.setNode(vertex.id, {
labelStyle: styles.labelStyle,
shape: _shape,
labelText: vertexText,
classData: vertex,
rx: radious,
ry: radious,
class: classStr,
style: styles.style,
id: vertex.id,
width: vertex.type === 'group' ? 500 : undefined,
type: vertex.type,
padding: getConfig().flowchart.padding
});
logger.info('setNode', {
labelStyle: styles.labelStyle,
shape: _shape,
labelText: vertexText,
rx: radious,
ry: radious,
class: classStr,
style: styles.style,
id: vertex.id,
width: vertex.type === 'group' ? 500 : undefined,
type: vertex.type,
padding: getConfig().flowchart.padding
});
});
};
/**
* Add edges to graph based on parsed graph defninition
* @param {Object} edges The edges to add to the graph
* @param {Object} g The graph object
*/
export const addRelations = function(relations, g) {
let cnt = 0;
let defaultStyle;
let defaultLabelStyle;
// if (typeof relations.defaultStyle !== 'undefined') {
// const defaultStyles = getStylesFromArray(relations.defaultStyle);
// defaultStyle = defaultStyles.style;
// defaultLabelStyle = defaultStyles.labelStyle;
// }
relations.forEach(function(edge) {
cnt++;
const edgeData = {};
//Set relationship style and line type
edgeData.classes = 'relation';
edgeData.pattern = edge.relation.lineType == 1 ? 'dashed' : 'solid';
edgeData.id = 'id' + cnt;
// Set link type for rendering
if (edge.type === 'arrow_open') {
edgeData.arrowhead = 'none';
} else {
edgeData.arrowhead = 'normal';
}
logger.info(edgeData, edge);
//Set relation arrow types
edgeData.arrowTypeStart = getArrowMarker(edge.relation.type1);
edgeData.arrowTypeEnd = getArrowMarker(edge.relation.type2);
let style = '';
let labelStyle = '';
if (typeof edge.style !== 'undefined') {
const styles = getStylesFromArray(edge.style);
style = styles.style;
labelStyle = styles.labelStyle;
} else {
style = 'fill:none';
if (typeof defaultStyle !== 'undefined') {
style = defaultStyle;
}
if (typeof defaultLabelStyle !== 'undefined') {
labelStyle = defaultLabelStyle;
}
}
edgeData.style = style;
edgeData.labelStyle = labelStyle;
if (typeof edge.interpolate !== 'undefined') {
edgeData.curve = interpolateToCurve(edge.interpolate, curveLinear);
} else if (typeof relations.defaultInterpolate !== 'undefined') {
edgeData.curve = interpolateToCurve(relations.defaultInterpolate, curveLinear);
} else {
edgeData.curve = interpolateToCurve(conf.curve, curveLinear);
}
edge.text = edge.title;
if (typeof edge.text === 'undefined') {
if (typeof edge.style !== 'undefined') {
edgeData.arrowheadStyle = 'fill: #333';
}
} else {
edgeData.arrowheadStyle = 'fill: #333';
edgeData.labelpos = 'c';
if (getConfig().flowchart.htmlLabels && false) { // eslint-disable-line
edgeData.labelType = 'html';
edgeData.label = '<span class="edgeLabel">' + edge.text + '</span>';
} else {
edgeData.labelType = 'text';
edgeData.label = edge.text.replace(common.lineBreakRegex, '\n');
if (typeof edge.style === 'undefined') {
edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none';
}
edgeData.labelStyle = edgeData.labelStyle.replace('color:', 'fill:');
}
}
// Add the edge to the graph
g.setEdge(edge.id1, edge.id2, edgeData, cnt);
});
};
// Todo optimize
const getGraphId = function(label) {
const keys = Object.keys(idCache);
for (let i = 0; i < keys.length; i++) {
if (idCache[keys[i]].label === label) {
return keys[i];
}
}
return undefined;
};
export const setConf = function(cnf) {
const keys = Object.keys(cnf);
keys.forEach(function(key) {
conf[key] = cnf[key];
});
};
/**
* Draws a flowchart in the tag with id: id based on the graph definition in text.
* @param text
* @param id
*/
export const drawOld = function(text, id) {
idCache = {};
parser.yy.clear();
parser.parse(text);
logger.info('Rendering diagram ' + text);
// Fetch the default direction, use TD if none was found
const diagram = select(`[id='${id}']`);
// insertMarkers(diagram);
// Layout graph, Create a new directed graph
const g = new graphlib.Graph({
multigraph: true
});
// Set an object for the graph label
g.setGraph({
isMultiGraph: true
});
// Default to assigning a new object as a label for each new edge.
g.setDefaultEdgeLabel(function() {
return {};
});
const classes = classDb.getClasses();
logger.info('classes:');
logger.info(classes);
const keys = Object.keys(classes);
for (let i = 0; i < keys.length; i++) {
const classDef = classes[keys[i]];
const node = svgDraw.drawClass(diagram, classDef, conf);
idCache[node.id] = node;
// Add nodes to the graph. The first argument is the node id. The second is
// metadata about the node. In this case we're going to add labels to each of
// our nodes.
g.setNode(node.id, node);
logger.info('Org height: ' + node.height);
}
const relations = classDb.getRelations();
logger.info('relations:', relations);
relations.forEach(function(relation) {
logger.info(
'tjoho' + getGraphId(relation.id1) + getGraphId(relation.id2) + JSON.stringify(relation)
);
g.setEdge(
getGraphId(relation.id1),
getGraphId(relation.id2),
{
relation: relation
},
relation.title || 'DEFAULT'
);
});
dagre.layout(g);
g.nodes().forEach(function(v) {
if (typeof v !== 'undefined' && typeof g.node(v) !== 'undefined') {
logger.debug('Node ' + v + ': ' + JSON.stringify(g.node(v)));
select('#' + lookUpDomId(v)).attr(
'transform',
'translate(' +
(g.node(v).x - g.node(v).width / 2) +
',' +
(g.node(v).y - g.node(v).height / 2) +
' )'
);
}
});
g.edges().forEach(function(e) {
if (typeof e !== 'undefined' && typeof g.edge(e) !== 'undefined') {
logger.debug('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(g.edge(e)));
svgDraw.drawEdge(diagram, g.edge(e), g.edge(e).relation, conf);
}
});
const svgBounds = diagram.node().getBBox();
const width = svgBounds.width + padding * 2;
const height = svgBounds.height + padding * 2;
if (conf.useMaxWidth) {
diagram.attr('width', '100%');
diagram.attr('style', `max-width: ${width}px;`);
} else {
diagram.attr('height', height);
diagram.attr('width', width);
}
// Ensure the viewBox includes the whole svgBounds area with extra space for padding
const vBox = `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`;
logger.debug(`viewBox ${vBox}`);
diagram.attr('viewBox', vBox);
};
export const draw = function(text, id) {
logger.info('Drawing class');
classDb.clear();
// const parser = classDb.parser;
// parser.yy = classDb;
// Parse the graph definition
// try {
parser.parse(text);
// } catch (err) {
// logger.debug('Parsing failed');
// }
// Fetch the default direction, use TD if none was found
let dir = 'TD';
const conf = getConfig().flowchart;
logger.info('config:', conf);
const nodeSpacing = conf.nodeSpacing || 50;
const rankSpacing = conf.rankSpacing || 50;
// Create the input mermaid.graph
const g = new graphlib.Graph({
multigraph: true,
compound: true
})
.setGraph({
rankdir: dir,
nodesep: nodeSpacing,
ranksep: rankSpacing,
marginx: 8,
marginy: 8
})
.setDefaultEdgeLabel(function() {
return {};
});
// let subG;
// const subGraphs = flowDb.getSubGraphs();
// logger.info('Subgraphs - ', subGraphs);
// for (let i = subGraphs.length - 1; i >= 0; i--) {
// subG = subGraphs[i];
// logger.info('Subgraph - ', subG);
// flowDb.addVertex(subG.id, subG.title, 'group', undefined, subG.classes);
// }
// Fetch the verices/nodes and edges/links from the parsed graph definition
const classes = classDb.getClasses();
const relations = classDb.getRelations();
logger.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);
// Add custom shapes
// flowChartShapes.addToRenderV2(addShape);
// Set up an SVG group so that we can translate the final graph.
const svg = select(`[id="${id}"]`);
// Run the renderer. This is what draws the final graph.
const element = 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;
logger.debug(
`new ViewBox 0 0 ${width} ${height}`,
`translate(${padding - g._label.marginx}, ${padding - g._label.marginy})`
);
if (conf.useMaxWidth) {
svg.attr('width', '100%');
svg.attr('style', `max-width: ${width}px;`);
} else {
svg.attr('height', height);
svg.attr('width', width);
}
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);
// Add label rects for non html labels
if (!conf.htmlLabels) {
const labels = document.querySelectorAll('[id="' + id + '"] .edgeLabel .label');
for (let k = 0; k < labels.length; k++) {
const label = labels[k];
// Get dimensions of label
const dim = label.getBBox();
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
rect.setAttribute('rx', 0);
rect.setAttribute('ry', 0);
rect.setAttribute('width', dim.width);
rect.setAttribute('height', dim.height);
rect.setAttribute('style', 'fill:#e8e8e8;');
label.insertBefore(rect, label.firstChild);
}
}
// If node has a link, wrap it in an anchor SVG object.
// const keys = Object.keys(classes);
// keys.forEach(function(key) {
// const vertex = classes[key];
// if (vertex.link) {
// const node = select('#' + id + ' [id="' + key + '"]');
// if (node) {
// const link = document.createElementNS('http://www.w3.org/2000/svg', 'a');
// link.setAttributeNS('http://www.w3.org/2000/svg', 'class', vertex.classes.join(' '));
// link.setAttributeNS('http://www.w3.org/2000/svg', 'href', vertex.link);
// link.setAttributeNS('http://www.w3.org/2000/svg', 'rel', 'noopener');
// const linkNode = node.insert(function() {
// return link;
// }, ':first-child');
// const shape = node.select('.label-container');
// if (shape) {
// linkNode.append(function() {
// return shape.node();
// });
// }
// const label = node.select('.label');
// if (label) {
// linkNode.append(function() {
// return label.node();
// });
// }
// }
// }
// });
};
export default {
setConf,
draw
};
function getArrowMarker(type) {
let marker;
switch (type) {
case 0:
marker = 'aggregation';
break;
case 1:
marker = 'extension';
break;
case 2:
marker = 'composition';
break;
case 3:
marker = 'dependency';
break;
default:
marker = 'none';
}
return marker;
}

View File

@ -6,24 +6,31 @@
/* lexical grammar */
%lex
%x string generic struct
%x string generic struct open_directive type_directive arg_directive
%%
\%\%[^\n]*\n* /* do nothing */
\n+ return 'NEWLINE';
\%\%\{ { this.begin('open_directive'); return 'open_directive'; }
<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)* /* skip comments */
(\r?\n)+ return 'NEWLINE';
\s+ /* skip whitespace */
"classDiagram-v2" return 'CLASS_DIAGRAM';
"classDiagram" return 'CLASS_DIAGRAM';
[\{] { this.begin("struct"); /*console.log('Starting struct');*/return 'STRUCT_START';}
[{] { this.begin("struct"); /*console.log('Starting struct');*/ return 'STRUCT_START';}
<struct><<EOF>> return "EOF_IN_STRUCT";
<struct>[\{] return "OPEN_IN_STRUCT";
<struct>\} { /*console.log('Ending struct');*/this.popState(); return 'STRUCT_STOP';}}
<struct>[\n] /* nothing */
<struct>[^\{\}\n]* { /*console.log('lex-member: ' + yytext);*/ return "MEMBER";}
<struct>[{] return "OPEN_IN_STRUCT";
<struct>[}] { /*console.log('Ending struct');*/this.popState(); return 'STRUCT_STOP';}}
<struct>[\n] /* nothing */
<struct>[^{}\n]* { /*console.log('lex-member: ' + yytext);*/ return "MEMBER";}
"class" return 'CLASS';
//"click" return 'CLICK';
//"click" return 'CLICK';
"callback" return 'CALLBACK';
"link" return 'LINK';
"<<" return 'ANNOTATION_START';
@ -40,7 +47,7 @@
\s*\|\> return 'EXTENSION';
\s*\> return 'DEPENDENCY';
\s*\< return 'DEPENDENCY';
\s*\* return 'COMPOSITION';
\s*\* return 'COMPOSITION';
\s*o return 'AGGREGATION';
\-\- return 'LINE';
\.\. return 'DOTTED_LINE';
@ -53,7 +60,7 @@
\= return 'EQUALS';
\w+ return 'ALPHA';
[!"#$%&'*+,-.`?\\/] return 'PUNCTUATION';
[0-9]+ return 'NUM';
[0-9]+ return 'NUM';
[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|
[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|
[\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5]|
@ -125,11 +132,39 @@
%left '^'
%start mermaidDoc
%start start
%% /* language grammar */
mermaidDoc: graphConfig;
start
: mermaidDoc
| directive start
;
mermaidDoc
: graphConfig
;
directive
: openDirective typeDirective closeDirective NEWLINE
| openDirective typeDirective ':' argDirective closeDirective NEWLINE
;
openDirective
: open_directive { yy.parseDirective('%%{', 'open_directive'); }
;
typeDirective
: type_directive { yy.parseDirective($1, 'type_directive'); }
;
argDirective
: arg_directive { $1 = $1.trim().replace(/'/g, '"'); yy.parseDirective($1, 'arg_directive'); }
;
closeDirective
: close_directive { yy.parseDirective('}%%', 'close_directive', 'class'); }
;
graphConfig
: CLASS_DIAGRAM NEWLINE statements EOF
@ -155,6 +190,7 @@ statement
| methodStatement
| annotationStatement
| clickStatement
| directive
;
classStatement

View File

@ -0,0 +1,114 @@
const getStyles = options =>
`g.classGroup text {
fill: ${options.nodeBorder};
fill: ${options.classText};
stroke: none;
font-family: ${options.fontFamily};
font-size: 10px;
.title {
font-weight: bolder;
}
}
.node rect,
.node circle,
.node ellipse,
.node polygon,
.node path {
fill: ${options.mainBkg};
stroke: ${options.nodeBorder};
stroke-width: 1px;
}
.divider {
stroke: ${options.nodeBorder};
stroke: 1;
}
g.clickable {
cursor: pointer;
}
g.classGroup rect {
fill: ${options.nodeBkg};
stroke: ${options.nodeBorder};
}
g.classGroup line {
stroke: ${options.nodeBorder};
stroke-width: 1;
}
.classLabel .box {
stroke: none;
stroke-width: 0;
fill: ${options.nodeBkg};
opacity: 0.5;
}
.classLabel .label {
fill: ${options.nodeBorder};
font-size: 10px;
}
.relation {
stroke: ${options.lineColor};
stroke-width: 1;
fill: none;
}
.dashed-line{
stroke-dasharray: 3;
}
#compositionStart, .composition {
fill: ${options.lineColor} !important;
stroke: ${options.lineColor} !important;
stroke-width: 1;
}
#compositionEnd, .composition {
fill: ${options.lineColor} !important;
stroke: ${options.lineColor} !important;
stroke-width: 1;
}
#dependencyStart, .dependency {
fill: ${options.lineColor} !important;
stroke: ${options.lineColor} !important;
stroke-width: 1;
}
#dependencyStart, .dependency {
fill: ${options.lineColor} !important;
stroke: ${options.lineColor} !important;
stroke-width: 1;
}
#extensionStart, .extension {
fill: ${options.lineColor} !important;
stroke: ${options.lineColor} !important;
stroke-width: 1;
}
#extensionEnd, .extension {
fill: ${options.lineColor} !important;
stroke: ${options.lineColor} !important;
stroke-width: 1;
}
#aggregationStart, .aggregation {
fill: ${options.nodeBkg} !important;
stroke: ${options.lineColor} !important;
stroke-width: 1;
}
#aggregationEnd, .aggregation {
fill: ${options.nodeBkg} !important;
stroke: ${options.lineColor} !important;
stroke-width: 1;
}
`;
export default getStyles;

View File

@ -278,13 +278,13 @@ export const drawClass = function(elem, classDef, conf) {
};
export const parseMember = function(text) {
const fieldRegEx = /^(\+|-|~|#)?(\w+)(~\w+~|\[\])?\s+(\w+)$/;
const methodRegEx = /^(\+|-|~|#)?(\w+)\s?\(\s*(\w+(~\w+~|\[\])?\s*(\w+)?)?\s*\)\s?([*|$])?\s?(\w+(~\w+~|\[\])?)?\s*$/;
const fieldRegEx = /(\+|-|~|#)?(\w+)(~\w+~|\[\])?\s+(\w+)/;
const methodRegEx = /^([+|\-|~|#])?(\w+) *\( *(.*)\) *(\*|\$)? *(\w*[~|[\]]*\s*\w*~?)$/;
let fieldMatch = text.match(fieldRegEx);
let methodMatch = text.match(methodRegEx);
if (fieldMatch) {
if (fieldMatch && !methodMatch) {
return buildFieldDisplay(fieldMatch);
} else if (methodMatch) {
return buildMethodDisplay(methodMatch);
@ -294,56 +294,78 @@ export const parseMember = function(text) {
};
const buildFieldDisplay = function(parsedText) {
let visibility = parsedText[1] ? parsedText[1].trim() : '';
let fieldType = parsedText[2] ? parsedText[2].trim() : '';
let genericType = parsedText[3] ? parseGenericTypes(parsedText[3]) : '';
let fieldName = parsedText[4] ? parsedText[4].trim() : '';
let displayText = '';
try {
let visibility = parsedText[1] ? parsedText[1].trim() : '';
let fieldType = parsedText[2] ? parsedText[2].trim() : '';
let genericType = parsedText[3] ? parseGenericTypes(parsedText[3].trim()) : '';
let fieldName = parsedText[4] ? parsedText[4].trim() : '';
displayText = visibility + fieldType + genericType + ' ' + fieldName;
} catch (err) {
displayText = parsedText;
}
return {
displayText: visibility + fieldType + genericType + ' ' + fieldName,
displayText: displayText,
cssStyle: ''
};
};
const buildMethodDisplay = function(parsedText) {
let cssStyle = '';
let displayText = parsedText;
let displayText = '';
let visibility = parsedText[1] ? parsedText[1].trim() : '';
let methodName = parsedText[2] ? parsedText[2].trim() : '';
let parameters = parsedText[3] ? parseGenericTypes(parsedText[3]) : '';
let classifier = parsedText[6] ? parsedText[6].trim() : '';
let returnType = parsedText[7] ? ' : ' + parseGenericTypes(parsedText[7]).trim() : '';
try {
let visibility = parsedText[1] ? parsedText[1].trim() : '';
let methodName = parsedText[2] ? parsedText[2].trim() : '';
let parameters = parsedText[3] ? parseGenericTypes(parsedText[3].trim()) : '';
let classifier = parsedText[4] ? parsedText[4].trim() : '';
let returnType = parsedText[5] ? ' : ' + parseGenericTypes(parsedText[5]).trim() : '';
displayText = visibility + methodName + '(' + parameters + ')' + returnType;
displayText = visibility + methodName + '(' + parameters + ')' + returnType;
cssStyle = parseClassifier(classifier);
cssStyle = parseClassifier(classifier);
} catch (err) {
displayText = parsedText;
}
let member = {
return {
displayText: displayText,
cssStyle: cssStyle
};
return member;
};
const buildLegacyDisplay = function(text) {
// if for some reason we dont have any match, use old format to parse text
let memberText = '';
let displayText = '';
let cssStyle = '';
let memberText = '';
let returnType = '';
let methodStart = text.indexOf('(');
let methodEnd = text.indexOf(')');
if (methodStart > 1 && methodEnd > methodStart && methodEnd <= text.length) {
let parsedText = text.match(/(\+|-|~|#)?(\w+)/);
let visibility = parsedText[1] ? parsedText[1].trim() : '';
let methodName = parsedText[2];
let visibility = '';
let methodName = '';
let firstChar = text.substring(0, 1);
if (firstChar.match(/\w/)) {
methodName = text.substring(0, methodStart).trim();
} else {
if (firstChar.match(/\+|-|~|#/)) {
visibility = firstChar;
}
methodName = text.substring(1, methodStart).trim();
}
let parameters = text.substring(methodStart + 1, methodEnd);
let classifier = text.substring(methodEnd, methodEnd + 1);
let classifier = text.substring(methodEnd + 1, 1);
cssStyle = parseClassifier(classifier);
memberText = visibility + methodName + '(' + parseGenericTypes(parameters.trim()) + ')';
displayText = visibility + methodName + '(' + parseGenericTypes(parameters.trim()) + ')';
if (methodEnd < memberText.length) {
returnType = text.substring(methodEnd + 2).trim();
@ -353,15 +375,13 @@ const buildLegacyDisplay = function(text) {
}
} else {
// finally - if all else fails, just send the text back as written (other than parsing for generic types)
memberText = parseGenericTypes(text);
displayText = parseGenericTypes(text);
}
let member = {
displayText: memberText + returnType,
return {
displayText: displayText,
cssStyle: cssStyle
};
return member;
};
const addTspan = function(textEl, txt, isFirst, conf) {

View File

@ -83,6 +83,14 @@ describe('class member Renderer, ', function () {
expect(actual.cssStyle).toBe('');
});
it('should handle simple method declaration with multiple parameters', function () {
const str = 'foo(int id, object thing)';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo(int id, object thing)');
expect(actual.cssStyle).toBe('');
});
it('should handle simple method declaration with single item in parameters', function () {
const str = 'foo(id)';
let actual = svgDraw.parseMember(str);

View File

@ -5,21 +5,52 @@ export const getRows = s => {
return str.split('#br#');
};
export const removeScript = txt => {
var rs = '';
var idx = 0;
while (idx >= 0) {
idx = txt.indexOf('<script');
if (idx >= 0) {
rs += txt.substr(0, idx);
txt = txt.substr(idx + 1);
idx = txt.indexOf('</script>');
if (idx >= 0) {
idx += 9;
txt = txt.substr(idx);
}
} else {
rs += txt;
idx = -1;
break;
}
}
return rs;
};
export const sanitizeText = (text, config) => {
let txt = text;
let htmlLabels = true;
if (
config.flowchart &&
(config.flowchart.htmlLabels === false || config.flowchart.htmlLabels === 'false')
)
) {
htmlLabels = false;
}
if (config.securityLevel !== 'loose' && htmlLabels) {
// eslint-disable-line
txt = breakToPlaceholder(txt);
txt = txt.replace(/</g, '&lt;').replace(/>/g, '&gt;');
txt = txt.replace(/=/g, '&equals;');
txt = placeholderToBreak(txt);
if (htmlLabels) {
const level = config.securityLevel;
if (level === 'antiscript') {
txt = removeScript(txt);
} else if (level !== 'loose') {
// eslint-disable-line
txt = breakToPlaceholder(txt);
txt = txt.replace(/</g, '&lt;').replace(/>/g, '&gt;');
txt = txt.replace(/=/g, '&equals;');
txt = placeholderToBreak(txt);
}
}
return txt;
@ -27,6 +58,14 @@ export const sanitizeText = (text, config) => {
export const lineBreakRegex = /<br\s*\/?>/gi;
export const hasBreaks = text => {
return /<br\s*[/]?>/gi.test(text);
};
export const splitBreaks = text => {
return text.split(/<br\s*[/]?>/gi);
};
const breakToPlaceholder = s => {
return s.replace(lineBreakRegex, '#br#');
};
@ -38,5 +77,8 @@ const placeholderToBreak = s => {
export default {
getRows,
sanitizeText,
lineBreakRegex
hasBreaks,
splitBreaks,
lineBreakRegex,
removeScript
};

View File

@ -0,0 +1,26 @@
import { removeScript } from './common';
describe('when securityLevel is antiscript, all script must be removed', function() {
it('should remove all script block, script inline.', function() {
const labelString = `1
Act1: Hello 1<script src="http://abc.com/script1.js"></script>1
<b>Act2</b>:
1<script>
alert('script run......');
</script>1
1`;
const result = removeScript(labelString);
const hasScript = (result.indexOf("script") >= 0);
expect(hasScript).toEqual(false);
const exactlyString = `1
Act1: Hello 11
<b>Act2</b>:
11
1`;
const isEqual = (result == exactlyString);
expect(isEqual).toEqual(true);
});
});

View File

@ -2,6 +2,8 @@
*
*/
import { logger } from '../../logger';
import mermaidAPI from '../../mermaidAPI';
import configApi from '../../config';
let entities = {};
let relationships = [];
@ -19,6 +21,10 @@ const Identification = {
IDENTIFYING: 'IDENTIFYING'
};
export const parseDirective = function(statement, context, type) {
mermaidAPI.parseDirective(this, statement, context, type);
};
const addEntity = function(name) {
if (typeof entities[name] === 'undefined') {
entities[name] = name;
@ -67,6 +73,8 @@ const clear = function() {
export default {
Cardinality,
Identification,
parseDirective,
getConfig: () => configApi.getConfig().er,
addEntity,
getEntities,
addRelationship,

View File

@ -43,6 +43,7 @@ const drawEntities = function(svgNode, entities, graph) {
const textId = 'entity-' + id;
const textNode = groupNode
.append('text')
.attr('class', 'er entityLabel')
.attr('id', textId)
.attr('x', 0)
.attr('y', 0)
@ -65,6 +66,7 @@ const drawEntities = function(svgNode, entities, graph) {
// Draw the rectangle - insert it before the text so that the text is not obscured
const rectNode = groupNode
.insert('rect', '#' + textId)
.attr('class', 'er entityBox')
.attr('fill', conf.fill)
.attr('fill-opacity', '100%')
.attr('stroke', conf.stroke)
@ -148,6 +150,7 @@ const drawRelationshipFromLayout = function(svg, rel, g, insert) {
// Insert the line at the right place
const svgPath = svg
.insert('path', '#' + insert)
.attr('class', 'er relationshipLine')
.attr('d', lineFunction(edge.points))
.attr('stroke', conf.stroke)
.attr('fill', 'none');
@ -224,6 +227,7 @@ const drawRelationshipFromLayout = function(svg, rel, g, insert) {
const labelNode = svg
.append('text')
.attr('class', 'er relationshipLabel')
.attr('id', labelId)
.attr('x', labelPoint.x)
.attr('y', labelPoint.y)
@ -241,6 +245,7 @@ const drawRelationshipFromLayout = function(svg, rel, g, insert) {
// Insert the opaque rectangle before the text label
svg
.insert('rect', '#' + labelId)
.attr('class', 'er relationshipLabelBox')
.attr('x', labelPoint.x - labelBBox.width / 2)
.attr('y', labelPoint.y - labelBBox.height / 2)
.attr('width', labelBBox.width)
@ -339,9 +344,14 @@ export const draw = function(text, id) {
const width = svgBounds.width + padding * 2;
const height = svgBounds.height + padding * 2;
svg.attr('height', height);
svg.attr('width', '100%');
svg.attr('style', `max-width: ${width}px;`);
if (conf.useMaxWidth) {
svg.attr('width', '100%');
svg.attr('style', `max-width: ${width}px;`);
} else {
svg.attr('height', height);
svg.attr('width', width);
}
svg.attr('viewBox', `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`);
}; // draw

View File

@ -1,8 +1,17 @@
%lex
%options case-insensitive
%x open_directive type_directive arg_directive
%%
\%\%\{ { this.begin('open_directive'); return 'open_directive'; }
<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]* /* skip comments */
[^\}]\%\%[^\n]* /* skip comments */
[\n]+ return 'NEWLINE';
\s+ /* skip whitespace */
[\s]+ return 'SPACE';
\"[^"]*\" return 'WORD';
@ -29,21 +38,36 @@ o\{ return 'ZERO_OR_MORE';
start
: 'ER_DIAGRAM' document 'EOF' { /*console.log('finished parsing');*/ }
| directive start
;
document
: /* empty */
| document statement
;
: /* empty */ { $$ = [] }
| document line {$1.push($2);$$ = $1}
;
line
: SPACE statement { $$ = $2 }
| statement { $$ = $1 }
| NEWLINE { $$=[];}
| EOF { $$=[];}
;
directive
: openDirective typeDirective closeDirective 'NEWLINE'
| openDirective typeDirective ':' argDirective closeDirective 'NEWLINE'
;
statement
: entityName relSpec entityName ':' role
: directive
| entityName relSpec entityName ':' role
{
yy.addEntity($1);
yy.addEntity($3);
yy.addEntity($1);
yy.addEntity($3);
yy.addRelationship($1, $5, $3, $2);
/*console.log($1 + $2 + $3 + ':' + $5);*/
};
}
;
entityName
: 'ALPHANUM' { $$ = $1; /*console.log('Entity: ' + $1);*/ }
@ -62,7 +86,7 @@ cardinality
| 'ZERO_OR_MORE' { $$ = yy.Cardinality.ZERO_OR_MORE; }
| 'ONE_OR_MORE' { $$ = yy.Cardinality.ONE_OR_MORE; }
| 'ONLY_ONE' { $$ = yy.Cardinality.ONLY_ONE; }
;
;
relType
: 'NON_IDENTIFYING' { $$ = yy.Identification.NON_IDENTIFYING; }
@ -73,4 +97,21 @@ role
: 'WORD' { $$ = $1.replace(/"/g, ''); }
| 'ALPHANUM' { $$ = $1; }
;
openDirective
: open_directive { yy.parseDirective('%%{', 'open_directive'); }
;
typeDirective
: type_directive { yy.parseDirective($1, 'type_directive'); }
;
argDirective
: arg_directive { $1 = $1.trim().replace(/'/g, '"'); yy.parseDirective($1, 'arg_directive'); }
;
closeDirective
: close_directive { yy.parseDirective('}%%', 'close_directive', 'er'); }
;
%%

22
src/diagrams/er/styles.js Normal file
View File

@ -0,0 +1,22 @@
const getStyles = options =>
`
.entityBox {
fill: ${options.mainBkg};
stroke: ${options.nodeBorder};
}
.relationshipLabelBox {
fill: ${options.tertiaryColor};
opacity: 0.3;
background-color: ${options.tertiaryColor};
rect {
opacity: 0.5;
}
}
.relationshipLine {
stroke: ${options.lineColor};
}
`;
export default getStyles;

View File

@ -1,13 +1,13 @@
import { select } from 'd3';
import { logger } from '../../logger'; // eslint-disable-line
import utils from '../../utils';
import { getConfig } from '../../config';
import configApi, { getConfig } from '../../config';
import common from '../common/common';
import mermaidAPI from '../../mermaidAPI';
// const MERMAID_DOM_ID_PREFIX = 'mermaid-dom-id-';
const MERMAID_DOM_ID_PREFIX = '';
const config = getConfig();
let config = getConfig();
let vertices = {};
let edges = [];
let classes = [];
@ -20,6 +20,10 @@ let direction;
// Functions to be run after graph rendering
let funs = [];
export const parseDirective = function(statement, context, type) {
mermaidAPI.parseDirective(this, statement, context, type);
};
/**
* Function called by parser when a node definition has been found
* @param id
@ -44,6 +48,7 @@ export const addVertex = function(_id, text, type, style, classes) {
vertices[id] = { id: id, styles: [], classes: [] };
}
if (typeof text !== 'undefined') {
config = getConfig();
txt = common.sanitizeText(text.trim(), config);
// strip quotes if string starts and ends with a quote
@ -219,7 +224,7 @@ const setTooltip = function(ids, tooltip) {
const setClickFun = function(_id, functionName) {
let id = _id;
if (_id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id;
if (config.securityLevel !== 'loose') {
if (getConfig().securityLevel !== 'loose') {
return;
}
if (typeof functionName === 'undefined') {
@ -232,7 +237,7 @@ const setClickFun = function(_id, functionName) {
elem.addEventListener(
'click',
function() {
window[functionName](id);
utils.runFunc(functionName, id);
},
false
);
@ -324,6 +329,7 @@ const setupToolTips = function(element) {
.on('mouseover', function() {
const el = select(this);
const title = el.attr('title');
// Dont try to draw a tooltip if no data is provided
if (title === null) {
return;
@ -336,8 +342,8 @@ const setupToolTips = function(element) {
.style('opacity', '.9');
tooltipElem
.html(el.attr('title'))
.style('left', rect.left + (rect.right - rect.left) / 2 + 'px')
.style('top', rect.top - 14 + document.body.scrollTop + 'px');
.style('left', window.scrollX + rect.left + (rect.right - rect.left) / 2 + 'px')
.style('top', window.scrollY + rect.top - 14 + document.body.scrollTop + 'px');
el.classed('hover', true);
})
.on('mouseout', function() {
@ -615,6 +621,8 @@ const destructLink = (_str, _startStr) => {
};
export default {
parseDirective,
getConfig: () => configApi.getConfig().flowchart,
addVertex,
addLink,
updateLinkInterpolate,

View File

@ -181,8 +181,15 @@ export const addEdges = function(edges, g) {
edges.forEach(function(edge) {
cnt++;
// Identify Link
var linkId = 'L-' + edge.start + '-' + edge.end;
var linkNameStart = 'LS-' + edge.start;
var linkNameEnd = 'LE-' + edge.end;
const edgeData = {};
edgeData.id = 'id' + cnt;
//edgeData.id = 'id' + cnt;
// Set link type for rendering
if (edge.type === 'arrow_open') {
edgeData.arrowhead = 'none';
@ -190,8 +197,34 @@ export const addEdges = function(edges, g) {
edgeData.arrowhead = 'normal';
}
logger.info(edgeData, edge);
edgeData.arrowType = edge.type;
// Check of arrow types, placed here in order not to break old rendering
edgeData.arrowTypeStart = 'arrow_open';
edgeData.arrowTypeEnd = 'arrow_open';
/* eslint-disable no-fallthrough */
switch (edge.type) {
case 'double_arrow_cross':
edgeData.arrowTypeStart = 'arrow_cross';
case 'arrow_cross':
edgeData.arrowTypeEnd = 'arrow_cross';
break;
case 'double_arrow_point':
edgeData.arrowTypeStart = 'arrow_point';
case 'arrow_point':
edgeData.arrowTypeEnd = 'arrow_point';
break;
case 'double_arrow_circle':
edgeData.arrowTypeStart = 'arrow_circle';
case 'arrow_circle':
edgeData.arrowTypeEnd = 'arrow_circle';
break;
}
// logger.info('apa', edgeData, edge);
// edgeData.arrowTypeStart = edge.arrowTypeStart;
// edgeData.arrowTypeStart = edge.arrowTypeStart;
// edgeData.arrowType = edgeData.arrowTypeEnd;
// logger.info('apa', edgeData, edge);
let style = '';
let labelStyle = '';
@ -210,12 +243,16 @@ export const addEdges = function(edges, g) {
if (typeof defaultLabelStyle !== 'undefined') {
labelStyle = defaultLabelStyle;
}
edgeData.thickness = 'normal';
edgeData.pattern = 'solid';
break;
case 'dotted':
style = 'fill:none;stroke-width:2px;stroke-dasharray:3;';
edgeData.thickness = 'normal';
edgeData.pattern = 'dotted';
break;
case 'thick':
style = ' stroke-width: 3.5px;fill:none';
edgeData.thickness = 'thick';
edgeData.pattern = 'solid';
break;
}
}
@ -241,7 +278,7 @@ export const addEdges = function(edges, g) {
if (getConfig().flowchart.htmlLabels && false) { // eslint-disable-line
edgeData.labelType = 'html';
edgeData.label = '<span class="edgeLabel">' + edge.text + '</span>';
edgeData.label = `<span id="L-${linkId}" class="edgeLabel L-${linkNameStart}' L-${linkNameEnd}">${edge.text}</span>`;
} else {
edgeData.labelType = 'text';
edgeData.label = edge.text.replace(common.lineBreakRegex, '\n');
@ -253,6 +290,10 @@ export const addEdges = function(edges, g) {
edgeData.labelStyle = edgeData.labelStyle.replace('color:', 'fill:');
}
}
edgeData.id = linkId;
edgeData.classes = 'flowchart-link ' + linkNameStart + ' ' + linkNameEnd;
// Add the edge to the graph
g.setEdge(edge.start, edge.end, edgeData, cnt);
});
@ -366,7 +407,7 @@ export const draw = function(text, id) {
return flowDb.getTooltip(this.id);
});
const padding = 8;
const padding = conf.diagramPadding;
const svgBounds = svg.node().getBBox();
const width = svgBounds.width + padding * 2;
const height = svgBounds.height + padding * 2;

View File

@ -166,6 +166,12 @@ export const addEdges = function(edges, g) {
edges.forEach(function(edge) {
cnt++;
// Identify Link
var linkId = 'L-' + edge.start + '-' + edge.end;
var linkNameStart = 'LS-' + edge.start;
var linkNameEnd = 'LE-' + edge.end;
const edgeData = {};
// Set link type for rendering
@ -223,7 +229,7 @@ export const addEdges = function(edges, g) {
if (getConfig().flowchart.htmlLabels) {
edgeData.labelType = 'html';
edgeData.label = '<span class="edgeLabel">' + edge.text + '</span>';
edgeData.label = `<span id="L-${linkId}" class="edgeLabel L-${linkNameStart}' L-${linkNameEnd}">${edge.text}</span>`;
} else {
edgeData.labelType = 'text';
edgeData.label = edge.text.replace(common.lineBreakRegex, '\n');
@ -235,6 +241,10 @@ export const addEdges = function(edges, g) {
edgeData.labelStyle = edgeData.labelStyle.replace('color:', 'fill:');
}
}
edgeData.id = linkId;
edgeData.class = linkNameStart + ' ' + linkNameEnd;
// Add the edge to the graph
g.setEdge(edge.start, edge.end, edgeData, cnt);
});
@ -384,7 +394,7 @@ export const draw = function(text, id) {
return flowDb.getTooltip(this.id);
});
const padding = 8;
const padding = conf.diagramPadding;
const svgBounds = svg.node().getBBox();
const width = svgBounds.width + padding * 2;
const height = svgBounds.height + padding * 2;

View File

@ -9,8 +9,19 @@
%x string
%x dir
%x vertex
%x open_directive
%x type_directive
%x arg_directive
%x close_directive
%%
\%\%[^\n]*\n* /* do nothing */
\%\%\{ { this.begin('open_directive'); return 'open_directive'; }
<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]* /* skip comments */
[^\}]\%\%[^\n]* /* skip comments */
["] this.begin("string");
<string>["] this.popState();
<string>[^"]* return "STR";
@ -25,6 +36,7 @@
"flowchart" {if(yy.lex.firstGraph()){this.begin("dir");} return 'GRAPH';}
"subgraph" return 'subgraph';
"end"\b\s* return 'end';
<dir>(\r?\n)*\s*\n { this.popState(); return 'NODIR'; }
<dir>\s*"LR" { this.popState(); return 'DIR'; }
<dir>\s*"RL" { this.popState(); return 'DIR'; }
<dir>\s*"TB" { this.popState(); return 'DIR'; }
@ -179,7 +191,7 @@
"{" return 'DIAMOND_START'
"}" return 'DIAMOND_STOP'
"\"" return 'QUOTE';
(\r|\n|\r\n)+ return 'NEWLINE';
(\r?\n)+ return 'NEWLINE';
\s return 'SPACE';
<<EOF>> return 'EOF';
@ -189,11 +201,39 @@
%left '^'
%start mermaidDoc
%start start
%% /* language grammar */
mermaidDoc: graphConfig document;
start
: mermaidDoc
| directive start
;
directive
: openDirective typeDirective closeDirective separator
| openDirective typeDirective ':' argDirective closeDirective separator
;
openDirective
: open_directive { yy.parseDirective('%%{', 'open_directive'); }
;
typeDirective
: type_directive { yy.parseDirective($1, 'type_directive'); }
;
argDirective
: arg_directive { $1 = $1.trim().replace(/'/g, '"'); yy.parseDirective($1, 'arg_directive'); }
;
closeDirective
: close_directive { yy.parseDirective('}%%', 'close_directive', 'flowchart'); }
;
mermaidDoc
: graphConfig document
;
document
: /* empty */
@ -218,6 +258,8 @@ line
graphConfig
: SPACE graphConfig
| NEWLINE graphConfig
| GRAPH NODIR
{ yy.setDirection('TB');$$ = 'TB';}
| GRAPH DIR FirstStmtSeperator
{ yy.setDirection($2);$$ = $2;}
// | GRAPH SPACE TAGEND FirstStmtSeperator

View File

@ -0,0 +1,75 @@
const getStyles = options =>
`.label {
font-family: ${options.fontFamily};
color: ${options.textColor};
}
.label text {
fill: ${options.textColor};
}
.node rect,
.node circle,
.node ellipse,
.node polygon,
.node path {
fill: ${options.mainBkg};
stroke: ${options.nodeBorder};
stroke-width: 1px;
}
.node .label {
text-align: center;
}
.node.clickable {
cursor: pointer;
}
.arrowheadPath {
fill: ${options.arrowheadColor};
}
.edgePath .path {
stroke: ${options.lineColor};
stroke-width: 1.5px;
}
.flowchart-link {
stroke: ${options.lineColor};
fill: none;
}
.edgeLabel {
background-color: ${options.edgeLabelBackground};
rect {
opacity: 0.5;
}
text-align: center;
}
.cluster rect {
fill: ${options.secondBkg};
stroke: ${options.clusterBorder};
stroke-width: 1px;
}
.cluster text {
fill: ${options.titleColor};
}
div.mermaidTooltip {
position: absolute;
text-align: center;
max-width: 200px;
padding: 2px;
font-family: ${options.fontFamily};
font-size: 12px;
background: ${options.secondBkg};
border: 1px solid ${options.border2};
border-radius: 2px;
pointer-events: none;
z-index: 100;
}
`;
export default getStyles;

View File

@ -1,9 +1,10 @@
import moment from 'moment-mini';
import { sanitizeUrl } from '@braintree/sanitize-url';
import { logger } from '../../logger';
import { getConfig } from '../../config';
import configApi, { getConfig } from '../../config';
import utils from '../../utils';
import mermaidAPI from '../../mermaidAPI';
const config = getConfig();
let dateFormat = '';
let axisFormat = '';
let todayMarker = '';
@ -16,6 +17,13 @@ const tags = ['active', 'done', 'crit', 'milestone'];
let funs = [];
let inclusiveEndDates = false;
// The serial order of the task in the script
let lastOrder = 0;
export const parseDirective = function(statement, context, type) {
mermaidAPI.parseDirective(this, statement, context, type);
};
export const clear = function() {
sections = [];
tasks = [];
@ -31,6 +39,7 @@ export const clear = function() {
todayMarker = '';
excludes = [];
inclusiveEndDates = false;
lastOrder = 0;
};
export const setAxisFormat = function(txt) {
@ -373,6 +382,9 @@ export const addTask = function(descr, data) {
rawTask.done = taskInfo.done;
rawTask.crit = taskInfo.crit;
rawTask.milestone = taskInfo.milestone;
rawTask.order = lastOrder;
lastOrder++;
const pos = rawTasks.push(rawTask);
@ -461,7 +473,7 @@ const compileTasks = function() {
*/
export const setLink = function(ids, _linkStr) {
let linkStr = _linkStr;
if (config.securityLevel !== 'loose') {
if (getConfig().securityLevel !== 'loose') {
linkStr = sanitizeUrl(_linkStr);
}
ids.split(',').forEach(function(id) {
@ -490,7 +502,7 @@ export const setClass = function(ids, className) {
};
const setClickFun = function(id, functionName, functionArgs) {
if (config.securityLevel !== 'loose') {
if (getConfig().securityLevel !== 'loose') {
return;
}
if (typeof functionName === 'undefined') {
@ -520,7 +532,7 @@ const setClickFun = function(id, functionName, functionArgs) {
let rawTask = findTaskById(id);
if (typeof rawTask !== 'undefined') {
pushFun(id, () => {
window[functionName](...argList);
utils.runFunc(functionName, ...argList);
});
}
};
@ -575,6 +587,8 @@ export const bindFunctions = function(element) {
};
export default {
parseDirective,
getConfig: () => configApi.getConfig().gantt,
clear,
setDateFormat,
getDateFormat,

View File

@ -176,6 +176,137 @@ describe('when using the ganttDb', function() {
expect(tasks[6].task).toEqual('test7');
});
it('should maintain the order in which tasks are created', function() {
ganttDb.setTitle('Project Execution');
ganttDb.setDateFormat('YYYY-MM-DD');
ganttDb.addSection('section A section');
ganttDb.addTask('Completed task', 'done, des1, 2014-01-06,2014-01-08');
ganttDb.addTask('Active task', 'active, des2, 2014-01-09, 3d');
ganttDb.addTask('Future task', 'des3, after des2, 5d');
ganttDb.addTask('Future task2', 'des4, after des3, 5d');
ganttDb.addSection('section Critical tasks');
ganttDb.addTask('Completed task in the critical line', 'crit, done, 2014-01-06,24h');
ganttDb.addTask('Implement parser and jison', 'crit, done, after des1, 2d');
ganttDb.addTask('Create tests for parser', 'crit, active, 3d');
ganttDb.addTask('Future task in critical line', 'crit, 5d');
ganttDb.addTask('Create tests for renderer', '2d');
ganttDb.addTask('Add to mermaid', '1d');
ganttDb.addSection('section Documentation');
ganttDb.addTask('Describe gantt syntax', 'active, a1, after des1, 3d');
ganttDb.addTask('Add gantt diagram to demo page', 'after a1 , 20h');
ganttDb.addTask('Add another diagram to demo page', 'doc1, after a1 , 48h');
ganttDb.addSection('section Last section');
ganttDb.addTask('Describe gantt syntax', 'after doc1, 3d');
ganttDb.addTask('Add gantt diagram to demo page', '20h');
ganttDb.addTask('Add another diagram to demo page', '48h');
const tasks = ganttDb.getTasks();
// Section - A section
expect(tasks[0].startTime).toEqual(moment('2014-01-06', 'YYYY-MM-DD').toDate());
expect(tasks[0].endTime).toEqual(moment('2014-01-08', 'YYYY-MM-DD').toDate());
expect(tasks[0].order).toEqual(0);
expect(tasks[0].id).toEqual('des1');
expect(tasks[0].task).toEqual('Completed task');
expect(tasks[1].startTime).toEqual(moment('2014-01-09', 'YYYY-MM-DD').toDate());
expect(tasks[1].endTime).toEqual(moment('2014-01-12', 'YYYY-MM-DD').toDate());
expect(tasks[1].order).toEqual(1);
expect(tasks[1].id).toEqual('des2');
expect(tasks[1].task).toEqual('Active task');
expect(tasks[2].startTime).toEqual(moment('2014-01-12', 'YYYY-MM-DD').toDate());
expect(tasks[2].endTime).toEqual(moment('2014-01-17', 'YYYY-MM-DD').toDate());
expect(tasks[2].order).toEqual(2);
expect(tasks[2].id).toEqual('des3');
expect(tasks[2].task).toEqual('Future task');
expect(tasks[3].startTime).toEqual(moment('2014-01-17', 'YYYY-MM-DD').toDate());
expect(tasks[3].endTime).toEqual(moment('2014-01-22', 'YYYY-MM-DD').toDate());
expect(tasks[3].order).toEqual(3);
expect(tasks[3].id).toEqual('des4');
expect(tasks[3].task).toEqual('Future task2');
// Section - Critical tasks
expect(tasks[4].startTime).toEqual(moment('2014-01-06', 'YYYY-MM-DD').toDate());
expect(tasks[4].endTime).toEqual(moment('2014-01-07', 'YYYY-MM-DD').toDate());
expect(tasks[4].order).toEqual(4);
expect(tasks[4].id).toEqual('task1');
expect(tasks[4].task).toEqual('Completed task in the critical line');
expect(tasks[5].startTime).toEqual(moment('2014-01-08', 'YYYY-MM-DD').toDate());
expect(tasks[5].endTime).toEqual(moment('2014-01-10', 'YYYY-MM-DD').toDate());
expect(tasks[5].order).toEqual(5);
expect(tasks[5].id).toEqual('task2');
expect(tasks[5].task).toEqual('Implement parser and jison');
expect(tasks[6].startTime).toEqual(moment('2014-01-10', 'YYYY-MM-DD').toDate());
expect(tasks[6].endTime).toEqual(moment('2014-01-13', 'YYYY-MM-DD').toDate());
expect(tasks[6].order).toEqual(6);
expect(tasks[6].id).toEqual('task3');
expect(tasks[6].task).toEqual('Create tests for parser');
expect(tasks[7].startTime).toEqual(moment('2014-01-13', 'YYYY-MM-DD').toDate());
expect(tasks[7].endTime).toEqual(moment('2014-01-18', 'YYYY-MM-DD').toDate());
expect(tasks[7].order).toEqual(7);
expect(tasks[7].id).toEqual('task4');
expect(tasks[7].task).toEqual('Future task in critical line');
expect(tasks[8].startTime).toEqual(moment('2014-01-18', 'YYYY-MM-DD').toDate());
expect(tasks[8].endTime).toEqual(moment('2014-01-20', 'YYYY-MM-DD').toDate());
expect(tasks[8].order).toEqual(8);
expect(tasks[8].id).toEqual('task5');
expect(tasks[8].task).toEqual('Create tests for renderer');
expect(tasks[9].startTime).toEqual(moment('2014-01-20', 'YYYY-MM-DD').toDate());
expect(tasks[9].endTime).toEqual(moment('2014-01-21', 'YYYY-MM-DD').toDate());
expect(tasks[9].order).toEqual(9);
expect(tasks[9].id).toEqual('task6');
expect(tasks[9].task).toEqual('Add to mermaid');
// Section - Documentation
expect(tasks[10].startTime).toEqual(moment('2014-01-08', 'YYYY-MM-DD').toDate());
expect(tasks[10].endTime).toEqual(moment('2014-01-11', 'YYYY-MM-DD').toDate());
expect(tasks[10].order).toEqual(10);
expect(tasks[10].id).toEqual('a1');
expect(tasks[10].task).toEqual('Describe gantt syntax');
expect(tasks[11].startTime).toEqual(moment('2014-01-11', 'YYYY-MM-DD').toDate());
expect(tasks[11].endTime).toEqual(moment('2014-01-11 20:00:00', 'YYYY-MM-DD HH:mm:ss').toDate());
expect(tasks[11].order).toEqual(11);
expect(tasks[11].id).toEqual('task7');
expect(tasks[11].task).toEqual('Add gantt diagram to demo page');
expect(tasks[12].startTime).toEqual(moment('2014-01-11', 'YYYY-MM-DD').toDate());
expect(tasks[12].endTime).toEqual(moment('2014-01-13', 'YYYY-MM-DD').toDate());
expect(tasks[12].order).toEqual(12);
expect(tasks[12].id).toEqual('doc1');
expect(tasks[12].task).toEqual('Add another diagram to demo page');
// Section - Last section
expect(tasks[13].startTime).toEqual(moment('2014-01-13', 'YYYY-MM-DD').toDate());
expect(tasks[13].endTime).toEqual(moment('2014-01-16', 'YYYY-MM-DD').toDate());
expect(tasks[13].order).toEqual(13);
expect(tasks[13].id).toEqual('task8');
expect(tasks[13].task).toEqual('Describe gantt syntax');
expect(tasks[14].startTime).toEqual(moment('2014-01-16', 'YYYY-MM-DD').toDate());
expect(tasks[14].endTime).toEqual(moment('2014-01-16 20:00:00', 'YYYY-MM-DD HH:mm:ss').toDate());
expect(tasks[14].order).toEqual(14);
expect(tasks[14].id).toEqual('task9');
expect(tasks[14].task).toEqual('Add gantt diagram to demo page');
expect(tasks[15].startTime).toEqual(moment('2014-01-16 20:00:00', 'YYYY-MM-DD HH:mm:ss').toDate());
expect(tasks[15].endTime).toEqual(moment('2014-01-18 20:00:00', 'YYYY-MM-DD HH:mm:ss').toDate());
expect(tasks[15].order).toEqual(15);
expect(tasks[15].id).toEqual('task10');
expect(tasks[15].task).toEqual('Add another diagram to demo page');
});
it('should work when end date is the 31st', function() {
ganttDb.setDateFormat('YYYY-MM-DD');
ganttDb.addSection('Task endTime is on the 31st day of the month');

View File

@ -80,6 +80,22 @@ export const draw = function(text, id) {
categories = checkUnique(categories);
function taskCompare(a, b) {
const taskA = a.startTime;
const taskB = b.startTime;
let result = 0;
if (taskA > taskB) {
result = 1;
} else if (taskA < taskB) {
result = -1;
}
return result;
}
// Sort the task array using the above taskCompare() so that
// tasks are created based on their order of startTime
taskArray.sort(taskCompare);
makeGant(taskArray, w, h);
if (typeof conf.useWidth !== 'undefined') {
elem.setAttribute('width', w);
@ -119,6 +135,8 @@ export const draw = function(text, id) {
.append('rect')
.attr('x', 0)
.attr('y', function(d, i) {
// Ignore the incoming i value and use our order instead
i = d.order;
return i * theGap + theTopPad - 2;
})
.attr('width', function() {
@ -160,6 +178,8 @@ export const draw = function(text, id) {
return timeScale(d.startTime) + theSidePad;
})
.attr('y', function(d, i) {
// Ignore the incoming i value and use our order instead
i = d.order;
return i * theGap + theTopPad;
})
.attr('width', function(d) {
@ -263,6 +283,8 @@ export const draw = function(text, id) {
}
})
.attr('y', function(d, i) {
// Ignore the incoming i value and use our order instead
i = d.order;
return i * theGap + conf.barHeight / 2 + (conf.fontSize / 2 - 2) + theTopPad;
})
.attr('text-height', theBarHeight)
@ -280,6 +302,7 @@ export const draw = function(text, id) {
}
let secNum = 0;
console.log(conf);
for (let i = 0; i < categories.length; i++) {
if (d.type === categories[i]) {
secNum = i % conf.numberSectionStyles;

View File

@ -11,7 +11,19 @@
%x href
%x callbackname
%x callbackargs
%x open_directive
%x type_directive
%x arg_directive
%x close_directive
%%
\%\%\{ { this.begin('open_directive'); return 'open_directive'; }
<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]* /* skip comments */
[^\}]\%\%*[^\n]* /* skip comments */
\%\%*[^\n]*[\n]* /* do nothing */
[\n]+ return 'NL';
\s+ /* skip whitespace */
@ -77,7 +89,8 @@ that id.
%% /* language grammar */
start
: gantt document 'EOF' { return $2; }
: directive start
| gantt document 'EOF' { return $2; }
;
document
@ -102,8 +115,14 @@ statement
| section {yy.addSection($1.substr(8));$$=$1.substr(8);}
| clickStatement
| taskTxt taskData {yy.addTask($1,$2);$$='task';}
| directive
;
directive
: openDirective typeDirective closeDirective 'NL'
| openDirective typeDirective ':' argDirective closeDirective 'NL'
;
/*
click allows any combination of href and call.
*/
@ -131,4 +150,22 @@ clickStatementDebug
| click href callbackname callbackargs {$$=$1 + ' ' + $2 + ' ' + $3 + ' ' + $4;}
| click href {$$=$1 + ' ' + $2;}
;%%
;
openDirective
: open_directive { yy.parseDirective('%%{', 'open_directive'); }
;
typeDirective
: type_directive { yy.parseDirective($1, 'type_directive'); }
;
argDirective
: arg_directive { $1 = $1.trim().replace(/'/g, '"'); yy.parseDirective($1, 'arg_directive'); }
;
closeDirective
: close_directive { yy.parseDirective('}%%', 'close_directive', 'gantt'); }
;
%%

View File

@ -0,0 +1,261 @@
const getStyles = options =>
`
.mermaid-main-font {
font-family: "trebuchet ms", verdana, arial;
font-family: var(--mermaid-font-family);
}
.section {
stroke: none;
opacity: 0.2;
}
.section0 {
fill: ${options.sectionBkgColor};
}
.section2 {
fill: ${options.sectionBkgColor2};
}
.section1,
.section3 {
fill: ${options.altSectionBkgColor};
opacity: 0.2;
}
.sectionTitle0 {
fill: ${options.titleColor};
}
.sectionTitle1 {
fill: ${options.titleColor};
}
.sectionTitle2 {
fill: ${options.titleColor};
}
.sectionTitle3 {
fill: ${options.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: ${options.gridColor};
opacity: 0.8;
shape-rendering: crispEdges;
text {
font-family: ${options.fontFamily};
fill: ${options.textColor};
}
}
.grid path {
stroke-width: 0;
}
/* Today line */
.today {
fill: none;
stroke: ${options.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: ${options.taskTextDarkColor};
text-anchor: start;
font-size: 11px;
font-family: 'trebuchet ms', verdana, arial;
font-family: var(--mermaid-font-family);
}
.taskTextOutsideLeft {
fill: ${options.taskTextDarkColor};
text-anchor: end;
font-size: 11px;
}
/* Special case clickable */
.task.clickable {
cursor: pointer;
}
.taskText.clickable {
cursor: pointer;
fill: ${options.taskTextClickableColor} !important;
font-weight: bold;
}
.taskTextOutsideLeft.clickable {
cursor: pointer;
fill: ${options.taskTextClickableColor} !important;
font-weight: bold;
}
.taskTextOutsideRight.clickable {
cursor: pointer;
fill: ${options.taskTextClickableColor} !important;
font-weight: bold;
}
/* Specific task settings for the sections*/
.taskText0,
.taskText1,
.taskText2,
.taskText3 {
fill: ${options.taskTextColor};
}
.task0,
.task1,
.task2,
.task3 {
fill: ${options.taskBkgColor};
stroke: ${options.taskBorderColor};
}
.taskTextOutside0,
.taskTextOutside2
{
fill: ${options.taskTextOutsideColor};
}
.taskTextOutside1,
.taskTextOutside3 {
fill: ${options.taskTextOutsideColor};
}
/* Active task */
.active0,
.active1,
.active2,
.active3 {
fill: ${options.activeTaskBkgColor};
stroke: ${options.activeTaskBorderColor};
}
.activeText0,
.activeText1,
.activeText2,
.activeText3 {
fill: ${options.taskTextDarkColor} !important;
}
/* Completed task */
.done0,
.done1,
.done2,
.done3 {
stroke: ${options.doneTaskBorderColor};
fill: ${options.doneTaskBkgColor};
stroke-width: 2;
}
.doneText0,
.doneText1,
.doneText2,
.doneText3 {
fill: ${options.taskTextDarkColor} !important;
}
/* Tasks on the critical line */
.crit0,
.crit1,
.crit2,
.crit3 {
stroke: ${options.critBorderColor};
fill: ${options.critBkgColor};
stroke-width: 2;
}
.activeCrit0,
.activeCrit1,
.activeCrit2,
.activeCrit3 {
stroke: ${options.critBorderColor};
fill: ${options.activeTaskBkgColor};
stroke-width: 2;
}
.doneCrit0,
.doneCrit1,
.doneCrit2,
.doneCrit3 {
stroke: ${options.critBorderColor};
fill: ${options.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: ${options.taskTextDarkColor} !important;
}
.activeCritText0,
.activeCritText1,
.activeCritText2,
.activeCritText3 {
fill: ${options.taskTextDarkColor} !important;
}
.titleText {
text-anchor: middle;
font-size: 18px;
fill: ${options.textColor} ;
font-family: 'trebuchet ms', verdana, arial;
font-family: var(--mermaid-font-family);
}
`;
export default getStyles;

View File

@ -1,5 +1,5 @@
import { logger } from '../../logger';
import { random } from '../../utils';
let commits = {};
let head = null;
let branches = { master: head };
@ -7,18 +7,8 @@ let curBranch = 'master';
let direction = 'LR';
let seq = 0;
function makeid(length) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for (var i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
function getId() {
return makeid(7);
return random({ length: 7 });
}
function isfastforwardable(currentCommit, otherCommit) {

View File

@ -1,10 +1,9 @@
/*
* Parse following
* gitGraph:
* commit
* commit
* branch
* branch
*/
%lex
@ -14,28 +13,28 @@
%%
(\r?\n)+ return 'NL';
\s+ /* skip all whitespace */
\#[^\n]* /* skip comments */
\%%[^\n]* /* skip comments */
"gitGraph" return 'GG';
"commit" return 'COMMIT';
"branch" return 'BRANCH';
"merge" return 'MERGE';
"reset" return 'RESET';
"checkout" return 'CHECKOUT';
"LR" return 'DIR';
"BT" return 'DIR';
":" return ':';
"^" return 'CARET'
"options"\r?\n this.begin("options");
<options>"end"\r?\n this.popState();
<options>[^\n]+\r?\n return 'OPT';
["] this.begin("string");
<string>["] this.popState();
<string>[^"]* return 'STR';
[a-zA-Z][a-zA-Z0-9_]+ return 'ID';
<<EOF>> return 'EOF';
(\r?\n)+ return 'NL';
\s+ /* skip all whitespace */
\#[^\n]* /* skip comments */
\%%[^\n]* /* skip comments */
"gitGraph" return 'GG';
"commit" return 'COMMIT';
"branch" return 'BRANCH';
"merge" return 'MERGE';
"reset" return 'RESET';
"checkout" return 'CHECKOUT';
"LR" return 'DIR';
"BT" return 'DIR';
":" return ':';
"^" return 'CARET'
"options"\r?\n this.begin("options");
<options>"end"\r?\n this.popState();
<options>[^\n]+\r?\n return 'OPT';
["] this.begin("string");
<string>["] this.popState();
<string>[^"]* return 'STR';
[a-zA-Z][-_\.a-zA-Z0-9]*[-_a-zA-Z0-9] return 'ID';
<<EOF>> return 'EOF';
/lex

View File

@ -0,0 +1,13 @@
const getStyles = () =>
`
.commit-id,
.commit-msg,
.branch-label {
fill: lightgrey;
color: lightgrey;
font-family: 'trebuchet ms', verdana, arial;
font-family: var(--mermaid-font-family);
}
`;
export default getStyles;

Some files were not shown because too many files have changed in this diff Show More