Merge branch 'master' of github.com:mermaid-js/mermaid

This commit is contained in:
Knut Sveidqvist 2021-09-23 18:52:57 +02:00
commit b2fb9f421a
63 changed files with 64603 additions and 3580 deletions

View File

@ -4,7 +4,7 @@
"es6": true, "es6": true,
"node": true "node": true
}, },
"parser": "babel-eslint", "parser": "@babel/eslint-parser",
"parserOptions": { "parserOptions": {
"ecmaFeatures": { "ecmaFeatures": {
"experimentalObjectRestSpread": true, "experimentalObjectRestSpread": true,

View File

@ -1,13 +1,12 @@
version: 2 version: 2
updates: updates:
- package-ecosystem: npm - package-ecosystem: npm
directory: / directory: /
target-branch: develop target-branch: develop
schedule: schedule:
interval: daily interval: weekly
- package-ecosystem: github-actions - package-ecosystem: github-actions
directory: / directory: /
target-branch: develop target-branch: develop
schedule: schedule:
interval: daily interval: weekly

View File

@ -9,25 +9,19 @@ jobs:
matrix: matrix:
node-version: [16.x] node-version: [16.x]
steps: steps:
- uses: actions/checkout@v2.3.4 - uses: actions/checkout@v2
- name: Setup Node.js ${{ matrix.node-version }} - name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2.2.0 uses: actions/setup-node@v2
with: with:
cache: yarn
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
- name: Install Yarn - name: Install Yarn
run: npm i yarn --global run: npm i yarn --global
- name: Cache Node Modules
uses: actions/cache@v2.1.5
with:
path: .cache
key: ${{ runner.OS }}-build-${{ hashFiles('**/yarn.lock') }}
- name: Install Packages - name: Install Packages
run: | run: |
yarn config set cache-folder $GITHUB_WORKSPACE/.cache/yarn
yarn install --frozen-lockfile yarn install --frozen-lockfile
env: env:
CYPRESS_CACHE_FOLDER: .cache/Cypress CYPRESS_CACHE_FOLDER: .cache/Cypress
@ -36,7 +30,7 @@ jobs:
run: yarn build run: yarn build
- name: Upload Build as Artifact - name: Upload Build as Artifact
uses: actions/upload-artifact@v2.2.3 uses: actions/upload-artifact@v2
with: with:
name: dist name: dist
path: dist path: dist
@ -61,4 +55,4 @@ jobs:
# uses: coverallsapp/github-action@master # uses: coverallsapp/github-action@master
# with: # with:
# github-token: ${{ secrets.GITHUB_TOKEN }} # github-token: ${{ secrets.GITHUB_TOKEN }}
# parallel-finished: true # parallel-finished: true

View File

@ -12,22 +12,16 @@ jobs:
- uses: actions/checkout@v2.3.4 - uses: actions/checkout@v2.3.4
- name: Setup Node.js ${{ matrix.node-version }} - name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2.2.0 uses: actions/setup-node@v2
with: with:
cache: yarn
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
- name: Install Yarn - name: Install Yarn
run: npm i yarn --global run: npm i yarn --global
- name: Cache Node Modules
uses: actions/cache@v2.1.5
with:
path: .cache
key: ${{ runner.OS }}-build-${{ hashFiles('**/yarn.lock') }}
- name: Install Packages - name: Install Packages
run: | run: |
yarn config set cache-folder $GITHUB_WORKSPACE/.cache/yarn
yarn install --frozen-lockfile yarn install --frozen-lockfile
env: env:
CYPRESS_CACHE_FOLDER: .cache/Cypress CYPRESS_CACHE_FOLDER: .cache/Cypress
@ -55,4 +49,4 @@ jobs:
# uses: coverallsapp/github-action@master # uses: coverallsapp/github-action@master
# with: # with:
# github-token: ${{ secrets.GITHUB_TOKEN }} # github-token: ${{ secrets.GITHUB_TOKEN }}
# parallel-finished: true # parallel-finished: true

View File

@ -8,7 +8,7 @@ jobs:
triage: triage:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: andymckay/labeler@1.0.2 - uses: andymckay/labeler@1.0.3
with: with:
repo-token: "${{ secrets.GITHUB_TOKEN }}" repo-token: "${{ secrets.GITHUB_TOKEN }}"
labels: "Status: Triage" labels: "Status: Triage"

View File

@ -10,6 +10,6 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Draft Release - name: Draft Release
uses: toolmantim/release-drafter@v5.2.0 uses: toolmantim/release-drafter@v5
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -9,9 +9,9 @@ jobs:
publish: publish:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2.3.4 - uses: actions/checkout@v2
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v2.2.0 uses: actions/setup-node@v2
with: with:
node-version: 16.x node-version: 16.x
- name: Install Yarn - name: Install Yarn

View File

@ -12,7 +12,7 @@ jobs:
- uses: fregante/setup-git-user@v1 - uses: fregante/setup-git-user@v1
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v2.2.0 uses: actions/setup-node@v2
with: with:
node-version: 16.x node-version: 16.x
- name: Install Yarn - name: Install Yarn

View File

@ -1,4 +1,5 @@
{ {
"printWidth": 100, "printWidth": 100,
"singleQuote": true "singleQuote": true,
"endOfLine": "auto"
} }

View File

@ -6,6 +6,8 @@
**Thanks to all involved, people committing pull requests, people answering questions! 🙏** **Thanks to all involved, people committing pull requests, people answering questions! 🙏**
<a href="https://mermaid-js.github.io/mermaid/landing/" alt="Link to landing page for the book The Official Guide To mermaid.js"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/img/book-banner-pre-release.jpg"></a>
## About ## About
<!-- <Main description> --> <!-- <Main description> -->

View File

@ -3,8 +3,8 @@ module.exports = {
[ [
'@babel/preset-env', '@babel/preset-env',
{ {
targets: "defaults, ie >= 11, current node" targets: 'defaults, ie >= 11, current node',
} },
] ],
] ],
} };

View File

@ -370,4 +370,100 @@ describe('Class diagram V2', () => {
); );
cy.get('svg'); cy.get('svg');
}); });
it('16: should handle the direction statemment with TB', () => {
imgSnapshotTest(
`
classDiagram
direction TB
class Student {
-idCard : IdCard
}
class IdCard{
-id : int
-name : string
}
class Bike{
-id : int
-name : string
}
Student "1" --o "1" IdCard : carries
Student "1" --o "1" Bike : rides
`,
{logLevel : 1, flowchart: { "htmlLabels": false },}
);
cy.get('svg');
});
it('17: should handle the direction statemment with BT', () => {
imgSnapshotTest(
`
classDiagram
direction BT
class Student {
-idCard : IdCard
}
class IdCard{
-id : int
-name : string
}
class Bike{
-id : int
-name : string
}
Student "1" --o "1" IdCard : carries
Student "1" --o "1" Bike : rides
`,
{logLevel : 1, flowchart: { "htmlLabels": false },}
);
cy.get('svg');
});
it('17: should handle the direction statemment with RL', () => {
imgSnapshotTest(
`
classDiagram
direction RL
class Student {
-idCard : IdCard
}
class IdCard{
-id : int
-name : string
}
class Bike{
-id : int
-name : string
}
Student "1" --o "1" IdCard : carries
Student "1" --o "1" Bike : rides
`,
{logLevel : 1, flowchart: { "htmlLabels": false },}
);
cy.get('svg');
});
it('18: should handle the direction statemment with LR', () => {
imgSnapshotTest(
`
classDiagram
direction LR
class Student {
-idCard : IdCard
}
class IdCard{
-id : int
-name : string
}
class Bike{
-id : int
-name : string
}
Student "1" --o "1" IdCard : carries
Student "1" --o "1" Bike : rides
`,
{logLevel : 1, flowchart: { "htmlLabels": false },}
);
cy.get('svg');
});
}); });

View File

@ -1,406 +1,411 @@
/* eslint-env jest */ /* eslint-env jest */
import { imgSnapshotTest, renderGraph } from '../../helpers/util'; import { imgSnapshotTest, renderGraph } from '../../helpers/util';
describe('Class diagram', () => { describe('Class diagram', () => {
it('1: should render a simple class diagram', () => { it('1: should render a simple class diagram', () => {
imgSnapshotTest( imgSnapshotTest(
` `
classDiagram classDiagram
Class01 <|-- AveryLongClass : Cool Class01 <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01 &lt;&lt;interface&gt;&gt; Class01
Class03 *-- Class04 Class03 *-- Class04
Class05 o-- Class06 Class05 o-- Class06
Class07 .. Class08 Class07 .. Class08
Class09 --> C2 : Where am i? Class09 --> C2 : Where am i?
Class09 --* C3 Class09 --* C3
Class09 --|> Class07 Class09 --|> Class07
Class12 <|.. Class08 Class12 <|.. Class08
Class11 ..>Class12 Class11 ..>Class12
Class07 : equals() Class07 : equals()
Class07 : Object[] elementData Class07 : Object[] elementData
Class01 : size() Class01 : size()
Class01 : int chimp Class01 : int chimp
Class01 : int gorilla Class01 : int gorilla
Class01 : -int privateChimp Class01 : -int privateChimp
Class01 : +int publicGorilla Class01 : +int publicGorilla
Class01 : #int protectedMarmoset Class01 : #int protectedMarmoset
Class08 <--> C2: Cool label Class08 <--> C2: Cool label
class Class10 { class Class10 {
&lt;&lt;service&gt;&gt; &lt;&lt;service&gt;&gt;
int id int id
test() test()
} }
`, `,
{logLevel : 1} {logLevel : 1}
); );
cy.get('svg'); cy.get('svg');
}); });
it('2: should render a simple class diagrams with cardinality', () => { it('2: should render a simple class diagrams with cardinality', () => {
imgSnapshotTest( imgSnapshotTest(
` `
classDiagram classDiagram
Class01 "1" <|--|> "*" AveryLongClass : Cool Class01 "1" <|--|> "*" AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01 &lt;&lt;interface&gt;&gt; Class01
Class03 "1" *-- "*" Class04 Class03 "1" *-- "*" Class04
Class05 "1" o-- "many" Class06 Class05 "1" o-- "many" Class06
Class07 "1" .. "*" Class08 Class07 "1" .. "*" Class08
Class09 "1" --> "*" C2 : Where am i? Class09 "1" --> "*" C2 : Where am i?
Class09 "*" --* "*" C3 Class09 "*" --* "*" C3
Class09 "1" --|> "1" Class07 Class09 "1" --|> "1" Class07
Class07 : equals() Class07 : equals()
Class07 : Object[] elementData Class07 : Object[] elementData
Class01 : size() Class01 : size()
Class01 : int chimp Class01 : int chimp
Class01 : int gorilla Class01 : int gorilla
Class08 "1" <--> "*" C2: Cool label Class08 "1" <--> "*" C2: Cool label
class Class10 { class Class10 {
&lt;&lt;service&gt;&gt; &lt;&lt;service&gt;&gt;
int id int id
test() test()
} }
`, `,
{} {}
); );
cy.get('svg'); cy.get('svg');
}); });
it('3: should render a simple class diagram with different visibilities', () => { it('3: should render a simple class diagram with different visibilities', () => {
imgSnapshotTest( imgSnapshotTest(
` `
classDiagram classDiagram
Class01 <|-- AveryLongClass : Cool Class01 <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01 &lt;&lt;interface&gt;&gt; Class01
Class01 : -privateMethod() Class01 : -privateMethod()
Class01 : +publicMethod() Class01 : +publicMethod()
Class01 : #protectedMethod() Class01 : #protectedMethod()
Class01 : -int privateChimp Class01 : -int privateChimp
Class01 : +int publicGorilla Class01 : +int publicGorilla
Class01 : #int protectedMarmoset Class01 : #int protectedMarmoset
`, `,
{} {}
); );
cy.get('svg'); cy.get('svg');
}); });
it('4: should render a simple class diagram with comments', () => { it('4: should render a simple class diagram with comments', () => {
imgSnapshotTest( imgSnapshotTest(
` `
classDiagram classDiagram
%% this is a comment %% this is a comment
Class01 <|-- AveryLongClass : Cool Class01 <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01 &lt;&lt;interface&gt;&gt; Class01
Class03 *-- Class04 Class03 *-- Class04
Class05 o-- Class06 Class05 o-- Class06
Class07 .. Class08 Class07 .. Class08
Class09 --> C2 : Where am i? Class09 --> C2 : Where am i?
Class09 --* C3 Class09 --* C3
Class09 --|> Class07 Class09 --|> Class07
Class07 : equals() Class07 : equals()
Class07 : Object[] elementData Class07 : Object[] elementData
Class01 : size() Class01 : size()
Class01 : int chimp Class01 : int chimp
Class01 : int gorilla Class01 : int gorilla
Class08 <--> C2: Cool label Class08 <--> C2: Cool label
class Class10 { class Class10 {
&lt;&lt;service&gt;&gt; &lt;&lt;service&gt;&gt;
int id int id
test() test()
} }
`, `,
{} {}
); );
cy.get('svg'); cy.get('svg');
}); });
it('5: should render a simple class diagram with abstract method', () => { it('5: should render a simple class diagram with abstract method', () => {
imgSnapshotTest( imgSnapshotTest(
` `
classDiagram classDiagram
Class01 <|-- AveryLongClass : Cool Class01 <|-- AveryLongClass : Cool
Class01 : someMethod()* Class01 : someMethod()*
`, `,
{} {}
); );
cy.get('svg'); cy.get('svg');
}); });
it('6: should render a simple class diagram with static method', () => { it('6: should render a simple class diagram with static method', () => {
imgSnapshotTest( imgSnapshotTest(
` `
classDiagram classDiagram
Class01 <|-- AveryLongClass : Cool Class01 <|-- AveryLongClass : Cool
Class01 : someMethod()$ Class01 : someMethod()$
`, `,
{} {}
); );
cy.get('svg'); cy.get('svg');
}); });
it('7: should render a simple class diagram with Generic class', () => { it('7: should render a simple class diagram with Generic class', () => {
imgSnapshotTest( imgSnapshotTest(
` `
classDiagram classDiagram
class Class01~T~ class Class01~T~
Class01 : size() Class01 : size()
Class01 : int chimp Class01 : int chimp
Class01 : int gorilla Class01 : int gorilla
Class08 <--> C2: Cool label Class08 <--> C2: Cool label
class Class10~T~ { class Class10~T~ {
&lt;&lt;service&gt;&gt; &lt;&lt;service&gt;&gt;
int id int id
test() test()
} }
`, `,
{} {}
); );
cy.get('svg'); cy.get('svg');
}); });
it('8: should render a simple class diagram with Generic class and relations', () => { it('8: should render a simple class diagram with Generic class and relations', () => {
imgSnapshotTest( imgSnapshotTest(
` `
classDiagram classDiagram
Class01~T~ <|-- AveryLongClass : Cool Class01~T~ <|-- AveryLongClass : Cool
Class03~T~ *-- Class04~T~ Class03~T~ *-- Class04~T~
Class01 : size() Class01 : size()
Class01 : int chimp Class01 : int chimp
Class01 : int gorilla Class01 : int gorilla
Class08 <--> C2: Cool label Class08 <--> C2: Cool label
class Class10~T~ { class Class10~T~ {
&lt;&lt;service&gt;&gt; &lt;&lt;service&gt;&gt;
int id int id
test() test()
} }
`, `,
{} {}
); );
cy.get('svg'); cy.get('svg');
}); });
it('9: should render a simple class diagram with clickable link', () => { it('9: should render a simple class diagram with clickable link', () => {
imgSnapshotTest( imgSnapshotTest(
` `
classDiagram classDiagram
Class01~T~ <|-- AveryLongClass : Cool Class01~T~ <|-- AveryLongClass : Cool
Class03~T~ *-- Class04~T~ Class03~T~ *-- Class04~T~
Class01 : size() Class01 : size()
Class01 : int chimp Class01 : int chimp
Class01 : int gorilla Class01 : int gorilla
Class08 <--> C2: Cool label Class08 <--> C2: Cool label
class Class10~T~ { class Class10~T~ {
&lt;&lt;service&gt;&gt; &lt;&lt;service&gt;&gt;
int id int id
test() test()
} }
link Class01 "google.com" "A Tooltip" link Class01 "google.com" "A Tooltip"
`, `,
{} {}
); );
cy.get('svg'); cy.get('svg');
}); });
it('10: should render a simple class diagram with clickable callback', () => { it('10: should render a simple class diagram with clickable callback', () => {
imgSnapshotTest( imgSnapshotTest(
` `
classDiagram classDiagram
Class01~T~ <|-- AveryLongClass : Cool Class01~T~ <|-- AveryLongClass : Cool
Class03~T~ *-- Class04~T~ Class03~T~ *-- Class04~T~
Class01 : size() Class01 : size()
Class01 : int chimp Class01 : int chimp
Class01 : int gorilla Class01 : int gorilla
Class08 <--> C2: Cool label Class08 <--> C2: Cool label
class Class10~T~ { class Class10~T~ {
&lt;&lt;service&gt;&gt; &lt;&lt;service&gt;&gt;
int id int id
test() test()
} }
callback Class01 "functionCall" "A Tooltip" callback Class01 "functionCall" "A Tooltip"
`, `,
{} {}
); );
cy.get('svg'); cy.get('svg');
}); });
it('11: should render a simple class diagram with return type on method', () => { it('11: should render a simple class diagram with return type on method', () => {
imgSnapshotTest( imgSnapshotTest(
` `
classDiagram classDiagram
class Class10~T~ { class Class10~T~ {
int[] id int[] id
test(int[] ids) bool test(int[] ids) bool
testArray() bool[] testArray() bool[]
} }
`, `,
{} {}
); );
cy.get('svg'); cy.get('svg');
}); });
it('12: should render a simple class diagram with generic types', () => { it('12: should render a simple class diagram with generic types', () => {
imgSnapshotTest( imgSnapshotTest(
` `
classDiagram classDiagram
class Class10~T~ { class Class10~T~ {
int[] id int[] id
List~int~ ids List~int~ ids
test(List~int~ ids) List~bool~ test(List~int~ ids) List~bool~
testArray() bool[] testArray() bool[]
} }
`, `,
{} {}
); );
cy.get('svg'); cy.get('svg');
}); });
it('13: should render a simple class diagram with css classes applied', () => { it('13: should render a simple class diagram with css classes applied', () => {
imgSnapshotTest( imgSnapshotTest(
` `
classDiagram classDiagram
class Class10 { class Class10 {
int[] id int[] id
List~int~ ids List~int~ ids
test(List~int~ ids) List~bool~ test(List~int~ ids) List~bool~
testArray() bool[] testArray() bool[]
} }
cssClass "Class10" exClass class Class10:::exClass2
`, `,
{} {}
); );
cy.get('svg'); cy.get('svg');
}); });
it('14: should render a simple class diagram with css classes applied directly', () => { it('14: should render a simple class diagram with css classes applied directly', () => {
imgSnapshotTest( imgSnapshotTest(
` `
classDiagram classDiagram
class Class10:::exClass { class Class10:::exClass2 {
int[] id int[] id
List~int~ ids List~int~ ids
test(List~int~ ids) List~bool~ test(List~int~ ids) List~bool~
testArray() bool[] testArray() bool[]
} }
`, `,
{} {}
); );
cy.get('svg'); cy.get('svg');
}); });
it('15: should render a simple class diagram with css classes applied two multiple classes', () => { it('15: should render a simple class diagram with css classes applied two multiple classes', () => {
imgSnapshotTest( imgSnapshotTest(
` `
classDiagram classDiagram
class Class10 class Class10
class Class20 class Class20
cssClass "Class10, class20" exClass cssClass "Class10, Class20" exClass2
`, class Class20:::exClass2
{} `,
); {}
cy.get('svg'); );
}); cy.get('svg');
});
it('16: should render multiple class diagrams', () => {
imgSnapshotTest( it('16: should render multiple class diagrams', () => {
[ imgSnapshotTest(
` [
classDiagram `
Class01 "1" <|--|> "*" AveryLongClass : Cool classDiagram
&lt;&lt;interface&gt;&gt; Class01 Class01 "1" <|--|> "*" AveryLongClass : Cool
Class03 "1" *-- "*" Class04 &lt;&lt;interface&gt;&gt; Class01
Class05 "1" o-- "many" Class06 Class03 "1" *-- "*" Class04
Class07 "1" .. "*" Class08 Class05 "1" o-- "many" Class06
Class09 "1" --> "*" C2 : Where am i? Class07 "1" .. "*" Class08
Class09 "*" --* "*" C3 Class09 "1" --> "*" C2 : Where am i?
Class09 "1" --|> "1" Class07 Class09 "*" --* "*" C3
Class07 : equals() Class09 "1" --|> "1" Class07
Class07 : Object[] elementData Class07 : equals()
Class01 : size() Class07 : Object[] elementData
Class01 : int chimp Class01 : size()
Class01 : int gorilla Class01 : int chimp
Class08 "1" <--> "*" C2: Cool label Class01 : int gorilla
class Class10 { Class08 "1" <--> "*" C2: Cool label
&lt;&lt;service&gt;&gt; class Class10 {
int id &lt;&lt;service&gt;&gt;
test() int id
} test()
`, }
` `,
classDiagram `
Class01 "1" <|--|> "*" AveryLongClass : Cool classDiagram
&lt;&lt;interface&gt;&gt; Class01 Class01 "1" <|--|> "*" AveryLongClass : Cool
Class03 "1" *-- "*" Class04 &lt;&lt;interface&gt;&gt; Class01
Class05 "1" o-- "many" Class06 Class03 "1" *-- "*" Class04
Class07 "1" .. "*" Class08 Class05 "1" o-- "many" Class06
Class09 "1" --> "*" C2 : Where am i? Class07 "1" .. "*" Class08
Class09 "*" --* "*" C3 Class09 "1" --> "*" C2 : Where am i?
Class09 "1" --|> "1" Class07 Class09 "*" --* "*" C3
Class07 : equals() Class09 "1" --|> "1" Class07
Class07 : Object[] elementData Class07 : equals()
Class01 : size() Class07 : Object[] elementData
Class01 : int chimp Class01 : size()
Class01 : int gorilla Class01 : int chimp
Class08 "1" <--> "*" C2: Cool label Class01 : int gorilla
class Class10 { Class08 "1" <--> "*" C2: Cool label
&lt;&lt;service&gt;&gt; class Class10 {
int id &lt;&lt;service&gt;&gt;
test() int id
} test()
`, }
], `,
{} ],
); {}
cy.get('svg'); );
}); cy.get('svg');
});
it('17: should render a class diagram when useMaxWidth is true (default)', () => {
renderGraph( // it('17: should render a class diagram when useMaxWidth is true (default)', () => {
` // renderGraph(
classDiagram // `
Class01 <|-- AveryLongClass : Cool // classDiagram
Class01 : size() // Class01 <|-- AveryLongClass : Cool
Class01 : int chimp // Class01 : size()
Class01 : int gorilla // Class01 : int chimp
Class01 : -int privateChimp // Class01 : int gorilla
Class01 : +int publicGorilla // Class01 : -int privateChimp
Class01 : #int protectedMarmoset // Class01 : +int publicGorilla
`, // Class01 : #int protectedMarmoset
{ class: { useMaxWidth: true } } // `,
); // { class: { useMaxWidth: true } }
cy.get('svg') // );
.should((svg) => { // cy.get('svg')
expect(svg).to.have.attr('width', '100%'); // .should((svg) => {
expect(svg).to.have.attr('height', '218'); // expect(svg).to.have.attr('width', '100%');
const style = svg.attr('style'); // const height = parseFloat(svg.attr('height'));
expect(style).to.match(/^max-width: [\d.]+px;$/); // expect(height).to.be.within(332, 333);
const maxWidthValue = parseInt(style.match(/[\d.]+/g).join('')); // // expect(svg).to.have.attr('height', '218');
// use within because the absolute value can be slightly different depending on the environment ±5% // const style = svg.attr('style');
expect(maxWidthValue).to.be.within(160 * .95, 160 * 1.05); // expect(style).to.match(/^max-width: [\d.]+px;$/);
}); // const maxWidthValue = parseInt(style.match(/[\d.]+/g).join(''));
}); // // use within because the absolute value can be slightly different depending on the environment ±5%
// expect(maxWidthValue).to.be.within(203, 204);
it('18: should render a class diagram when useMaxWidth is false', () => { // });
renderGraph( // });
`
classDiagram // it('18: should render a class diagram when useMaxWidth is false', () => {
Class01 <|-- AveryLongClass : Cool // renderGraph(
Class01 : size() // `
Class01 : int chimp // classDiagram
Class01 : int gorilla // Class01 <|-- AveryLongClass : Cool
Class01 : -int privateChimp // Class01 : size()
Class01 : +int publicGorilla // Class01 : int chimp
Class01 : #int protectedMarmoset // Class01 : int gorilla
`, // Class01 : -int privateChimp
{ class: { useMaxWidth: false } } // Class01 : +int publicGorilla
); // Class01 : #int protectedMarmoset
cy.get('svg') // `,
.should((svg) => { // { class: { useMaxWidth: false } }
const width = parseFloat(svg.attr('width')); // );
// use within because the absolute value can be slightly different depending on the environment ±5% // cy.get('svg')
expect(width).to.be.within(160 * .95, 160 * 1.05); // .should((svg) => {
expect(svg).to.have.attr('height', '218'); // const width = parseFloat(svg.attr('width'));
expect(svg).to.not.have.attr('style'); // // use within because the absolute value can be slightly different depending on the environment ±5%
}); // expect(width).to.be.within(100, 101);
}); // const height = parseFloat(svg.attr('height'));
}); // expect(height).to.be.within(332, 333);
// // expect(svg).to.have.attr('height', '332');
// // expect(svg).to.not.have.attr('style');
// });
// });
});

View File

@ -101,7 +101,7 @@ describe('Flowchart v2', () => {
const style = svg.attr('style'); const style = svg.attr('style');
expect(style).to.match(/^max-width: [\d.]+px;$/); expect(style).to.match(/^max-width: [\d.]+px;$/);
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join('')); const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
expect(maxWidthValue).to.be.within(300 * .95-1, 300 * 1.05); expect(maxWidthValue).to.be.within(290 * .95-1, 290 * 1.05);
}); });
}); });
it('8: should render a flowchart when useMaxWidth is false', () => { it('8: should render a flowchart when useMaxWidth is false', () => {
@ -121,7 +121,7 @@ describe('Flowchart v2', () => {
const width = parseFloat(svg.attr('width')); const width = parseFloat(svg.attr('width'));
// use within because the absolute value can be slightly different depending on the environment ±5% // use within because the absolute value can be slightly different depending on the environment ±5%
expect(height).to.be.within(446 * .95, 446 * 1.05); expect(height).to.be.within(446 * .95, 446 * 1.05);
expect(width).to.be.within(300 * .95-1, 300 * 1.05); expect(width).to.be.within(290 * .95-1, 290 * 1.05);
expect(svg).to.not.have.attr('style'); expect(svg).to.not.have.attr('style');
}); });
}); });

View File

@ -584,7 +584,7 @@ context('Sequence diagram', () => {
expect(svg).to.have.attr('width', '100%'); expect(svg).to.have.attr('width', '100%');
expect(svg).to.have.attr('height'); expect(svg).to.have.attr('height');
const height = parseFloat(svg.attr('height')); const height = parseFloat(svg.attr('height'));
expect(height).to.eq(920); expect(height).to.be.within(920, 960);
const style = svg.attr('style'); const style = svg.attr('style');
expect(style).to.match(/^max-width: [\d.]+px;$/); expect(style).to.match(/^max-width: [\d.]+px;$/);
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join('')); const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
@ -624,7 +624,7 @@ context('Sequence diagram', () => {
.should((svg) => { .should((svg) => {
const height = parseFloat(svg.attr('height')); const height = parseFloat(svg.attr('height'));
const width = parseFloat(svg.attr('width')); const width = parseFloat(svg.attr('width'));
expect(height).to.eq(920); expect(height).to.be.within(920, 960);
// use within because the absolute value can be slightly different depending on the environment ±5% // use within because the absolute value can be slightly different depending on the environment ±5%
expect(width).to.be.within(820 * .95, 820 * 1.05); expect(width).to.be.within(820 * .95, 820 * 1.05);
expect(svg).to.not.have.attr('style'); expect(svg).to.not.have.attr('style');

View File

@ -452,7 +452,7 @@ stateDiagram-v2
expect(svg).to.have.attr('width', '100%'); expect(svg).to.have.attr('width', '100%');
expect(svg).to.have.attr('height'); expect(svg).to.have.attr('height');
const height = parseFloat(svg.attr('height')); const height = parseFloat(svg.attr('height'));
expect(height).to.eq(177); expect(height).to.be.within(177, 178);
const style = svg.attr('style'); const style = svg.attr('style');
expect(style).to.match(/^max-width: [\d.]+px;$/); expect(style).to.match(/^max-width: [\d.]+px;$/);
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join('')); const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
@ -474,7 +474,7 @@ stateDiagram-v2
.should((svg) => { .should((svg) => {
const height = parseFloat(svg.attr('height')); const height = parseFloat(svg.attr('height'));
const width = parseFloat(svg.attr('width')); const width = parseFloat(svg.attr('width'));
expect(height).to.eq(177); expect(height).to.be.within(177, 178);
// use within because the absolute value can be slightly different depending on the environment ±5% // use within because the absolute value can be slightly different depending on the environment ±5%
expect(width).to.be.within(135 * .95, 135 * 1.05); expect(width).to.be.within(135 * .95, 135 * 1.05);
expect(svg).to.not.have.attr('style'); expect(svg).to.not.have.attr('style');

View File

@ -10,7 +10,7 @@
<style> <style>
body { body {
/* background: rgb(221, 208, 208); */ /* background: rgb(221, 208, 208); */
/* background:#333; */ background:#333;
font-family: 'Arial'; font-family: 'Arial';
/* font-size: 18px !important; */ /* font-size: 18px !important; */
} }
@ -27,17 +27,22 @@
<div>info below</div> <div>info below</div>
<div class="flex"> <div class="flex">
<div class="mermaid3" style="width: 100%; height: 20%;"> <div class="mermaid2" style="width: 100%; height: 20%;">
stateDiagram-v2 classDiagram
state S1 { direction TB
sub1 -->sub2 class Student {
-idCard : IdCard
} }
class IdCard{
state S2 { -id : int
sub4 -name : string
} }
S1 --> S2 class Bike{
sub1 --> sub4 -id : int
-name : string
}
Student "1" --o "1" IdCard : carries
Student "1" --o "1" Bike : rides
</div> </div>
<div class="mermaid3" style="width: 100%; height: 20%;"> <div class="mermaid3" style="width: 100%; height: 20%;">
@ -46,17 +51,14 @@ stateDiagram
YourState123456789012345123456789123456789012345123456789123456789012345123456789123456789012345123456789 --> MyState:a label YourState123456789012345123456789123456789012345123456789123456789012345123456789123456789012345123456789 --> MyState:a label
} }
</div>
<div class="mermaid3" style="width: 100%; height: 20%;">
flowchart
subgraph CompositeState
subgraph AnotherCompositeStateCompositeStateCompositeStateCompositeState
YourState --a label--> MyState
end
end
</div> </div>
<div class="mermaid" style="width: 100%; height: 20%;"> <div class="mermaid" style="width: 100%; height: 20%;">
flowchart LR
one --> two
three -.-> four[whoa, big arrowhead nine o'clock]
</div>
<div class="mermaid2" style="width: 100%; height: 20%;">
%%{init: { "apa":"b", "theme":"forest"}}%% %%{init: { "apa":"b", "theme":"forest"}}%%
sequenceDiagram sequenceDiagram
Alice->>Bob: Hi Bob Alice->>Bob: Hi Bob
@ -110,12 +112,12 @@ YourState
// console.error('Mermaid error: ', err); // console.error('Mermaid error: ', err);
}; };
mermaid.initialize({ mermaid.initialize({
theme: 'base', theme: 'dark',
// theme: 'forest',
arrowMarkerAbsolute: true, arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}', // themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 2, logLevel: 2,
flowchart: { nodeSpacing: 10, curve: 'cardinal', htmlLabels: true }, flowchart: { nodeSpacing: 10, curve: 'cardinal', htmlLabels: false },
htmlLabels: true,
// gantt: { axisFormat: '%m/%d/%Y' }, // gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorFontFamily: 'courier',actorMargin: 50, showSequenceNumbers: false }, sequence: { actorFontFamily: 'courier',actorMargin: 50, showSequenceNumbers: false },
// sequenceDiagram: { actorMargin: 300 } // deprecated // sequenceDiagram: { actorMargin: 300 } // deprecated

562
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

64641
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

14
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

View File

@ -443,6 +443,46 @@ class Shape{
``` ```
## Setting the direction of the diagram
With class diagrams you can use the direction statement to set the direction which the diagram will render like in this example.
```
classDiagram
direction RL
class Student {
-idCard : IdCard
}
class IdCard{
-id : int
-name : string
}
class Bike{
-id : int
-name : string
}
Student "1" --o "1" IdCard : carries
Student "1" --o "1" Bike : rides
```
This is how this renders
```mermaid
classDiagram
direction RL
class Student {
-idCard : IdCard
}
class IdCard{
-id : int
-name : string
}
class Bike{
-id : int
-name : string
}
Student "1" --o "1" IdCard : carries
Student "1" --o "1" Bike : rides
```
## Interaction ## Interaction
It is possible to bind a click event to a node, the click can lead to either a javascript callback or to a link which will be opened in a new browser tab. **Note**: This functionality is disabled when using `securityLevel='strict'` and enabled when using `securityLevel='loose'`. It is possible to bind a click event to a node, the click can lead to either a javascript callback or to a link which will be opened in a new browser tab. **Note**: This functionality is disabled when using `securityLevel='strict'` and enabled when using `securityLevel='loose'`.

View File

@ -11,12 +11,12 @@ Node
### A node (default) ### A node (default)
``` ```
graph LR flowchart LR
id id
``` ```
```mermaid ```mermaid
graph LR flowchart LR
id id
``` ```
@ -29,11 +29,11 @@ found for the node that will be used. Also if you define edges for the node late
one previously defined will be used when rendering the box. one previously defined will be used when rendering the box.
``` ```
graph LR flowchart LR
id1[This is the text in the box] id1[This is the text in the box]
``` ```
```mermaid ```mermaid
graph LR flowchart LR
id1[This is the text in the box] id1[This is the text in the box]
``` ```
@ -41,25 +41,25 @@ graph LR
This statement declares the direction of the Flowchart. This statement declares the direction of the Flowchart.
This declares the graph is oriented from top to bottom (`TD` or `TB`). This declares the flowchart is oriented from top to bottom (`TD` or `TB`).
``` ```
graph TD flowchart TD
Start --> Stop Start --> Stop
``` ```
```mermaid ```mermaid
graph TD flowchart TD
Start --> Stop Start --> Stop
``` ```
This declares the graph is oriented from left to right (`LR`). This declares the flowchart is oriented from left to right (`LR`).
``` ```
graph LR flowchart LR
Start --> Stop Start --> Stop
``` ```
```mermaid ```mermaid
graph LR flowchart LR
Start --> Stop Start --> Stop
``` ```
@ -78,66 +78,66 @@ Possible FlowChart orientations are:
### A node with round edges ### A node with round edges
``` ```
graph LR flowchart LR
id1(This is the text in the box) id1(This is the text in the box)
``` ```
```mermaid ```mermaid
graph LR flowchart LR
id1(This is the text in the box) id1(This is the text in the box)
``` ```
### A stadium-shaped node ### A stadium-shaped node
``` ```
graph LR flowchart LR
id1([This is the text in the box]) id1([This is the text in the box])
``` ```
```mermaid ```mermaid
graph LR flowchart LR
id1([This is the text in the box]) id1([This is the text in the box])
``` ```
### A node in a subroutine shape ### A node in a subroutine shape
``` ```
graph LR flowchart LR
id1[[This is the text in the box]] id1[[This is the text in the box]]
``` ```
```mermaid ```mermaid
graph LR flowchart LR
id1[[This is the text in the box]] id1[[This is the text in the box]]
``` ```
### A node in a cylindrical shape ### A node in a cylindrical shape
``` ```
graph LR flowchart LR
id1[(Database)] id1[(Database)]
``` ```
```mermaid ```mermaid
graph LR flowchart LR
id1[(Database)] id1[(Database)]
``` ```
### A node in the form of a circle ### A node in the form of a circle
``` ```
graph LR flowchart LR
id1((This is the text in the circle)) id1((This is the text in the circle))
``` ```
```mermaid ```mermaid
graph LR flowchart LR
id1((This is the text in the circle)) id1((This is the text in the circle))
``` ```
### A node in an asymmetric shape ### A node in an asymmetric shape
``` ```
graph LR flowchart LR
id1>This is the text in the box] id1>This is the text in the box]
``` ```
```mermaid ```mermaid
graph LR flowchart LR
id1>This is the text in the box] id1>This is the text in the box]
``` ```
Currently only the shape above is possible and not its mirror. *This might change with future releases.* Currently only the shape above is possible and not its mirror. *This might change with future releases.*
@ -145,65 +145,65 @@ Currently only the shape above is possible and not its mirror. *This might chang
### A node (rhombus) ### A node (rhombus)
``` ```
graph LR flowchart LR
id1{This is the text in the box} id1{This is the text in the box}
``` ```
```mermaid ```mermaid
graph LR flowchart LR
id1{This is the text in the box} id1{This is the text in the box}
``` ```
### A hexagon node ### A hexagon node
``` ```
graph LR flowchart LR
id1{{This is the text in the box}} id1{{This is the text in the box}}
``` ```
```mermaid ```mermaid
graph LR flowchart LR
id1{{This is the text in the box}} id1{{This is the text in the box}}
``` ```
### Parallelogram ### Parallelogram
``` ```
graph TD flowchart TD
id1[/This is the text in the box/] id1[/This is the text in the box/]
``` ```
```mermaid ```mermaid
graph TD flowchart TD
id1[/This is the text in the box/] id1[/This is the text in the box/]
``` ```
### Parallelogram alt ### Parallelogram alt
``` ```
graph TD flowchart TD
id1[\This is the text in the box\] id1[\This is the text in the box\]
``` ```
```mermaid ```mermaid
graph TD flowchart TD
id1[\This is the text in the box\] id1[\This is the text in the box\]
``` ```
### Trapezoid ### Trapezoid
``` ```
graph TD flowchart TD
A[/Christmas\] A[/Christmas\]
``` ```
```mermaid ```mermaid
graph TD flowchart TD
A[/Christmas\] A[/Christmas\]
``` ```
### Trapezoid alt ### Trapezoid alt
``` ```
graph TD flowchart TD
B[\Go shopping/] B[\Go shopping/]
``` ```
```mermaid ```mermaid
graph TD flowchart TD
B[\Go shopping/] B[\Go shopping/]
``` ```
@ -214,110 +214,110 @@ Nodes can be connected with links/edges. It is possible to have different types
### A link with arrow head ### A link with arrow head
``` ```
graph LR flowchart LR
A-->B A-->B
``` ```
```mermaid ```mermaid
graph LR flowchart LR
A-->B A-->B
``` ```
### An open link ### An open link
``` ```
graph LR flowchart LR
A --- B A --- B
``` ```
```mermaid ```mermaid
graph LR flowchart LR
A --- B A --- B
``` ```
### Text on links ### Text on links
``` ```
graph LR flowchart LR
A-- This is the text! ---B A-- This is the text! ---B
``` ```
```mermaid ```mermaid
graph LR flowchart LR
A-- This is the text ---B A-- This is the text ---B
``` ```
or or
``` ```
graph LR flowchart LR
A---|This is the text|B A---|This is the text|B
``` ```
```mermaid ```mermaid
graph LR flowchart LR
A---|This is the text|B A---|This is the text|B
``` ```
### A link with arrow head and text ### A link with arrow head and text
``` ```
graph LR flowchart LR
A-->|text|B A-->|text|B
``` ```
```mermaid ```mermaid
graph LR flowchart LR
A-->|text|B A-->|text|B
``` ```
or or
``` ```
graph LR flowchart LR
A-- text -->B A-- text -->B
``` ```
```mermaid ```mermaid
graph LR flowchart LR
A-- text -->B A-- text -->B
``` ```
### Dotted link ### Dotted link
``` ```
graph LR; flowchart LR;
A-.->B; A-.->B;
``` ```
```mermaid ```mermaid
graph LR; flowchart LR;
A-.->B; A-.->B;
``` ```
### Dotted link with text ### Dotted link with text
``` ```
graph LR flowchart LR
A-. text .-> B A-. text .-> B
``` ```
```mermaid ```mermaid
graph LR flowchart LR
A-. text .-> B A-. text .-> B
``` ```
### Thick link ### Thick link
``` ```
graph LR flowchart LR
A ==> B A ==> B
``` ```
```mermaid ```mermaid
graph LR flowchart LR
A ==> B A ==> B
``` ```
### Thick link with text ### Thick link with text
``` ```
graph LR flowchart LR
A == text ==> B A == text ==> B
``` ```
```mermaid ```mermaid
graph LR flowchart LR
A == text ==> B A == text ==> B
``` ```
@ -325,48 +325,48 @@ graph LR
It is possible declare many links in the same line as per below: It is possible declare many links in the same line as per below:
``` ```
graph LR flowchart LR
A -- text --> B -- text2 --> C A -- text --> B -- text2 --> C
``` ```
```mermaid ```mermaid
graph LR flowchart LR
A -- text --> B -- text2 --> C A -- text --> B -- text2 --> C
``` ```
It is also possible to declare multiple nodes links in the same line as per below: It is also possible to declare multiple nodes links in the same line as per below:
``` ```
graph LR flowchart LR
a --> b & c--> d a --> b & c--> d
``` ```
```mermaid ```mermaid
graph LR flowchart LR
a --> b & c--> d a --> b & c--> d
``` ```
You can then describe dependencies in a very expressive way. Like the one-liner below: You can then describe dependencies in a very expressive way. Like the one-liner below:
``` ```
graph TB flowchart TB
A & B--> C & D A & B--> C & D
``` ```
```mermaid ```mermaid
graph TB flowchart TB
A & B--> C & D A & B--> C & D
``` ```
If you describe the same diagram using the the basic syntax, it will take four lines. A If you describe the same diagram using the the basic syntax, it will take four lines. A
word of warning, one could go overboard with this making the graph harder to read in word of warning, one could go overboard with this making the flowchart harder to read in
markdown form. The Swedish word `lagom` comes to mind. It means, not too much and not too little. markdown form. The Swedish word `lagom` comes to mind. It means, not too much and not too little.
This goes for expressive syntaxes as well. This goes for expressive syntaxes as well.
``` ```
graph TB flowchart TB
A --> C A --> C
A --> D A --> D
B --> C B --> C
B --> D B --> D
``` ```
### Beta: New arrow types ### New arrow types
When using flowchart instead of graph there are new types of arrows supported as per below: There are new types of arrows supported as per below:
``` ```
flowchart LR flowchart LR
@ -381,9 +381,9 @@ flowchart LR
``` ```
### Beta: Multi directional arrows ### Multi directional arrows
When using flowchart instead of graph there is the possibility to use multidirectional arrows. There is the possibility to use multidirectional arrows.
``` ```
flowchart LR flowchart LR
@ -411,7 +411,7 @@ In the following example, two extra dashes are added in the link from node _B_
to node _E_, so that it spans two more ranks than regular links: to node _E_, so that it spans two more ranks than regular links:
``` ```
graph TD flowchart TD
A[Start] --> B{Is it?}; A[Start] --> B{Is it?};
B -->|Yes| C[OK]; B -->|Yes| C[OK];
C --> D[Rethink]; C --> D[Rethink];
@ -420,7 +420,7 @@ graph TD
``` ```
```mermaid ```mermaid
graph TD flowchart TD
A[Start] --> B{Is it?}; A[Start] --> B{Is it?};
B -->|Yes| C[OK]; B -->|Yes| C[OK];
C --> D[Rethink]; C --> D[Rethink];
@ -436,7 +436,7 @@ be added on the right side of the link. The following example is equivalent to
the previous one: the previous one:
``` ```
graph TD flowchart TD
A[Start] --> B{Is it?}; A[Start] --> B{Is it?};
B -- Yes --> C[OK]; B -- Yes --> C[OK];
C --> D[Rethink]; C --> D[Rethink];
@ -445,7 +445,7 @@ graph TD
``` ```
```mermaid ```mermaid
graph TD flowchart TD
A[Start] --> B{Is it?}; A[Start] --> B{Is it?};
B -->|Yes| C[OK]; B -->|Yes| C[OK];
C --> D[Rethink]; C --> D[Rethink];
@ -470,11 +470,11 @@ as summed up in the following table:
It is possible to put text within quotes in order to render more troublesome characters. As in the example below: It is possible to put text within quotes in order to render more troublesome characters. As in the example below:
``` ```
graph LR flowchart LR
id1["This is the (text) in the box"] id1["This is the (text) in the box"]
``` ```
```mermaid ```mermaid
graph LR flowchart LR
id1["This is the (text) in the box"] id1["This is the (text) in the box"]
``` ```
@ -483,11 +483,11 @@ graph LR
It is possible to escape characters using the syntax exemplified here. It is possible to escape characters using the syntax exemplified here.
``` ```
graph LR flowchart LR
A["A double quote:#quot;"] -->B["A dec char:#9829;"] A["A double quote:#quot;"] -->B["A dec char:#9829;"]
``` ```
```mermaid ```mermaid
graph LR flowchart LR
A["A double quote:#quot;"] -->B["A dec char:#9829;"] A["A double quote:#quot;"] -->B["A dec char:#9829;"]
``` ```
@ -504,7 +504,7 @@ end
An example below: An example below:
``` ```
graph TB flowchart TB
c1-->a2 c1-->a2
subgraph one subgraph one
a1-->a2 a1-->a2
@ -517,7 +517,7 @@ graph TB
end end
``` ```
```mermaid ```mermaid
graph TB flowchart TB
c1-->a2 c1-->a2
subgraph one subgraph one
a1-->a2 a1-->a2
@ -533,14 +533,14 @@ graph TB
You can also set an explicit id for the subgraph. You can also set an explicit id for the subgraph.
``` ```
graph TB flowchart TB
c1-->a2 c1-->a2
subgraph ide1 [one] subgraph ide1 [one]
a1-->a2 a1-->a2
end end
``` ```
```mermaid ```mermaid
graph TB flowchart TB
c1-->a2 c1-->a2
subgraph id1 [one] subgraph id1 [one]
a1-->a2 a1-->a2
@ -549,7 +549,7 @@ graph TB
## Beta: flowcharts ## Beta: flowcharts
With the graphtype flowcharts it is also possible to set edges to and from subgraphs as in the graph below. With the graphtype flowcharts it is also possible to set edges to and from subgraphs as in the flowchart below.
``` ```
flowchart TB flowchart TB
@ -647,7 +647,7 @@ Examples of tooltip usage below:
``` ```
``` ```
graph LR; flowchart LR;
A-->B; A-->B;
B-->C; B-->C;
C-->D; C-->D;
@ -660,7 +660,7 @@ graph LR;
The tooltip text is surrounded in double quotes. The styles of the tooltip are set by the class .mermaidTooltip. The tooltip text is surrounded in double quotes. The styles of the tooltip are set by the class .mermaidTooltip.
```mermaid ```mermaid
graph LR flowchart LR
A-->B; A-->B;
B-->C; B-->C;
C-->D; C-->D;
@ -675,7 +675,7 @@ graph LR
Links are opened in the same browser tab/window by default. It is possible to change this by adding a link target to the click definition (`_self`, `_blank`, `_parent` and `_top` are supported): Links are opened in the same browser tab/window by default. It is possible to change this by adding a link target to the click definition (`_self`, `_blank`, `_parent` and `_top` are supported):
``` ```
graph LR; flowchart LR;
A-->B; A-->B;
B-->C; B-->C;
C-->D; C-->D;
@ -687,7 +687,7 @@ graph LR;
``` ```
```mermaid ```mermaid
graph LR; flowchart LR;
A-->B; A-->B;
B-->C; B-->C;
C-->D; C-->D;
@ -702,7 +702,7 @@ Beginners tip, a full example using interactive links in a html context:
```html ```html
<body> <body>
<div class="mermaid"> <div class="mermaid">
graph LR; flowchart LR;
A-->B; A-->B;
B-->C; B-->C;
C-->D; C-->D;
@ -736,7 +736,7 @@ Beginners tip, a full example using interactive links in a html context:
Comments can be entered within a flow diagram, which will be ignored by the parser. Comments need to be on their own line, and must be prefaced with `%%` (double percent signs). Any text after the start of the comment to the next newline will be treated as a comment, including any flow syntax Comments can be entered within a flow diagram, which will be ignored by the parser. Comments need to be on their own line, and must be prefaced with `%%` (double percent signs). Any text after the start of the comment to the next newline will be treated as a comment, including any flow syntax
``` ```
graph LR flowchart LR
%% this is a comment A -- text --> B{node} %% this is a comment A -- text --> B{node}
A -- text --> B -- text2 --> C A -- text --> B -- text2 --> C
``` ```
@ -760,13 +760,13 @@ linkStyle 3 stroke:#ff3,stroke-width:4px,color:red;
It is possible to apply specific styles such as a thicker border or a different background color to a node. It is possible to apply specific styles such as a thicker border or a different background color to a node.
``` ```
graph LR flowchart LR
id1(Start)-->id2(Stop) id1(Start)-->id2(Stop)
style id1 fill:#f9f,stroke:#333,stroke-width:4px style id1 fill:#f9f,stroke:#333,stroke-width:4px
style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5 style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
``` ```
```mermaid ```mermaid
graph LR flowchart LR
id1(Start)-->id2(Stop) id1(Start)-->id2(Stop)
style id1 fill:#f9f,stroke:#333,stroke-width:4px style id1 fill:#f9f,stroke:#333,stroke-width:4px
style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5 style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
@ -800,12 +800,12 @@ It is also possible to attach a class to a list of nodes in one statement:
A shorter form of adding a class is to attach the classname to the node using the `:::`operator as per below: A shorter form of adding a class is to attach the classname to the node using the `:::`operator as per below:
``` ```
graph LR flowchart LR
A:::someclass --> B A:::someclass --> B
classDef someclass fill:#f96; classDef someclass fill:#f96;
``` ```
```mermaid ```mermaid
graph LR flowchart LR
A:::someclass --> B A:::someclass --> B
classDef someclass fill:#f96; classDef someclass fill:#f96;
``` ```
@ -831,13 +831,13 @@ below:
**Example definition** **Example definition**
``` ```
graph LR; flowchart LR;
A-->B[AAA<span>BBB</span>]; A-->B[AAA<span>BBB</span>];
B-->D; B-->D;
class A cssClass; class A cssClass;
``` ```
```mermaid ```mermaid
graph LR; flowchart LR;
A-->B[AAA<span>BBB</span>]; A-->B[AAA<span>BBB</span>];
B-->D; B-->D;
class A cssClass; class A cssClass;
@ -860,14 +860,14 @@ It is possible to add icons from fontawesome.
The icons are accessed via the syntax fa:#icon class name#. The icons are accessed via the syntax fa:#icon class name#.
``` ```
graph TD flowchart TD
B["fa:fa-twitter for peace"] B["fa:fa-twitter for peace"]
B-->C[fa:fa-ban forbidden] B-->C[fa:fa-ban forbidden]
B-->D(fa:fa-spinner); B-->D(fa:fa-spinner);
B-->E(A fa:fa-camera-retro perhaps?); B-->E(A fa:fa-camera-retro perhaps?);
``` ```
```mermaid ```mermaid
graph TD flowchart TD
B["fa:fa-twitter for peace"] B["fa:fa-twitter for peace"]
B-->C[fa:fa-ban forbidden] B-->C[fa:fa-ban forbidden]
B-->D(fa:fa-spinner); B-->D(fa:fa-spinner);
@ -884,7 +884,7 @@ graph TD
Below is the new declaration of the graph edges which is also valid along with the old declaration of the graph edges. Below is the new declaration of the graph edges which is also valid along with the old declaration of the graph edges.
``` ```
graph LR flowchart LR
A[Hard edge] -->|Link text| B(Round edge) A[Hard edge] -->|Link text| B(Round edge)
B --> C{Decision} B --> C{Decision}
C -->|One| D[Result one] C -->|One| D[Result one]
@ -892,7 +892,7 @@ graph LR
``` ```
```mermaid ```mermaid
graph LR flowchart LR
A[Hard edge] -->|Link text| B(Round edge) A[Hard edge] -->|Link text| B(Round edge)
B --> C{Decision} B --> C{Decision}
C -->|One| D[Result one] C -->|One| D[Result one]

View File

@ -7,7 +7,7 @@
<meta name="description" content="Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs."> <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"> <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"> --> <!-- <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.10.2/dist/mermaid.min.js"></script> <link rel="stylesheet" href="theme.css"> <script src="//cdn.jsdelivr.net/npm/mermaid@8.12.0/dist/mermaid.min.js"></script>
<!-- <script src="http://localhost:9000/mermaid.js"></script> --> <!-- <script src="http://localhost:9000/mermaid.js"></script> -->
<script> <script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){

View File

@ -114,6 +114,8 @@ They also serve as proof of concept, for the variety of things that can be built
- [Mermaid plugin for google docs](https://workspace.google.com/marketplace/app/mermaid/636321283856) - [Mermaid plugin for google docs](https://workspace.google.com/marketplace/app/mermaid/636321283856)
- [Podlite](https://github.com/zag/podlite-desktop) - [Podlite](https://github.com/zag/podlite-desktop)
- [Named block =Diagram](https://github.com/zag/podlite/tree/main/packages/podlite-diagrams) - [Named block =Diagram](https://github.com/zag/podlite/tree/main/packages/podlite-diagrams)
- [GNU Nano](https://www.nano-editor.org/)
- [Nano Mermaid](https://github.com/Yash-Singh1/nano-mermaid)
## Document Generation ## Document Generation
@ -128,6 +130,8 @@ They also serve as proof of concept, for the variety of things that can be built
- [Type Doc](https://typedoc.org/) - [Type Doc](https://typedoc.org/)
- [typedoc-plugin-mermaid](https://www.npmjs.com/package/typedoc-plugin-mermaid) - [typedoc-plugin-mermaid](https://www.npmjs.com/package/typedoc-plugin-mermaid)
- [Docsy Hugo Theme](https://www.docsy.dev/docs/adding-content/lookandfeel/#diagrams-with-mermaid) (Native support in theme) - [Docsy Hugo Theme](https://www.docsy.dev/docs/adding-content/lookandfeel/#diagrams-with-mermaid) (Native support in theme)
- [Codedoc](https://codedoc.cc/)
- [codedoc-mermaid-plugin](https://www.npmjs.com/package/codedoc-mermaid-plugin)
## Browser Extensions ## Browser Extensions
@ -137,7 +141,7 @@ They also serve as proof of concept, for the variety of things that can be built
| GitHub + Mermaid | [🎡🔗](https://chrome.google.com/webstore/detail/github-%20-mermaid/goiiopgdnkogdbjmncgedmgpoajilohe) | [🦊🔗](https://addons.mozilla.org/firefox/addon/github-mermaid/) | - | - | [🐙🔗](https://github.com/BackMarket/github-mermaid-extension) | GitHub + Mermaid | [🎡🔗](https://chrome.google.com/webstore/detail/github-%20-mermaid/goiiopgdnkogdbjmncgedmgpoajilohe) | [🦊🔗](https://addons.mozilla.org/firefox/addon/github-mermaid/) | - | - | [🐙🔗](https://github.com/BackMarket/github-mermaid-extension)
| Asciidoctor Live Preview | [🎡🔗](https://chrome.google.com/webstore/detail/asciidoctorjs-live-previe/iaalpfgpbocpdfblpnhhgllgbdbchmia) | - | - | [🌀🔗](https://microsoftedge.microsoft.com/addons/detail/asciidoctorjs-live-previ/pefkelkanablhjdekgdahplkccnbdggd?hl=en-US) | -| | Asciidoctor Live Preview | [🎡🔗](https://chrome.google.com/webstore/detail/asciidoctorjs-live-previe/iaalpfgpbocpdfblpnhhgllgbdbchmia) | - | - | [🌀🔗](https://microsoftedge.microsoft.com/addons/detail/asciidoctorjs-live-previ/pefkelkanablhjdekgdahplkccnbdggd?hl=en-US) | -|
| Diagram Tab| -| - | - | - | [🐙🔗](https://github.com/khafast/diagramtab) | | Diagram Tab| -| - | - | - | [🐙🔗](https://github.com/khafast/diagramtab) |
| Markdown Diagrams| - | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-diagrams/) | [🔴🔗](https://addons.opera.com/en/extensions/details/markdown-diagrams/) | [🌀🔗](https://microsoftedge.microsoft.com/addons/detail/markdown-diagrams/hceenoomhhdkjjijnmlclkpenkapfihe) | [🐙🔗](https://github.com/marcozaccari/markdown-diagrams-browser-extension/tree/master/doc/examples) | | Markdown Diagrams| [🎡🔗](https://chrome.google.com/webstore/detail/markdown-diagrams/pmoglnmodacnbbofbgcagndelmgaclel/) | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-diagrams/) | [🔴🔗](https://addons.opera.com/en/extensions/details/markdown-diagrams/) | [🌀🔗](https://microsoftedge.microsoft.com/addons/detail/markdown-diagrams/hceenoomhhdkjjijnmlclkpenkapfihe) | [🐙🔗](https://github.com/marcozaccari/markdown-diagrams-browser-extension/tree/master/doc/examples) |
| Markdown Viewer| - | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-viewer-chrome/) | - | - | [🐙🔗](https://github.com/simov/markdown-viewer)| | Markdown Viewer| - | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-viewer-chrome/) | - | - | [🐙🔗](https://github.com/simov/markdown-viewer)|
| Extensions for Mermaid| - | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-viewer-chrome/) | [🔴🔗](https://addons.opera.com/en/extensions/details/extensions-for-mermaid/)| - | [🐙🔗](https://github.com/Stefan-S/mermaid-extension) | | Extensions for Mermaid| - | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-viewer-chrome/) | [🔴🔗](https://addons.opera.com/en/extensions/details/extensions-for-mermaid/)| - | [🐙🔗](https://github.com/Stefan-S/mermaid-extension) |
| Chrome Diagrammer| [🎡🔗](https://chrome.google.com/webstore/detail/chrome-diagrammer/bkpbgjmkomfoakfklcjeoegkklgjnnpk) | - |- | - | - | | Chrome Diagrammer| [🎡🔗](https://chrome.google.com/webstore/detail/chrome-diagrammer/bkpbgjmkomfoakfklcjeoegkklgjnnpk) | - |- | - | - |

View File

@ -63,6 +63,7 @@ A requirement definition contains a requirement type, name, id, text, risk, and
Type, risk, and method are enumerations defined in SysML. Type, risk, and method are enumerations defined in SysML.
| Keyword | Options | | Keyword | Options |
|---|---|
| Type | requirement, functionalRequirement, interfaceRequirement, performanceRequirement, physicalRequirement, designConstraint | | Type | requirement, functionalRequirement, interfaceRequirement, performanceRequirement, physicalRequirement, designConstraint |
| Risk | Low, Medium, High | | Risk | Low, Medium, High |
| VerifcationMethod | Analysis, Inspection, Test, Demonstration | | VerifcationMethod | Analysis, Inspection, Test, Demonstration |
@ -170,4 +171,4 @@ This example uses all features of the diagram.
test_req5 - refines -> test_req6 test_req5 - refines -> test_req6
test_entity3 - verifies -> test_req5 test_entity3 - verifies -> test_req5
test_req <- copies - test_entity2 test_req <- copies - test_entity2
``` ```

View File

@ -354,6 +354,37 @@ stateDiagram-v2
} }
``` ```
## Setting the direction of the diagram
With state diagrams you can use the direction statement to set the direction which the diagram will render like in this example.
```
stateDiagram
direction LR
[*] --> A
A --> B
B --> C
state B {
direction LR
a --> b
}
B --> D
```
This is how this renders
```mermaid
stateDiagram
direction LR
[*] --> A
A --> B
B --> C
state B {
direction LR
a --> b
}
B --> D
```
## Comments ## Comments
Comments can be entered within a state diagram chart, which will be ignored by the parser. Comments need to be on their own line, and must be prefaced with `%%` (double percent signs). Any text after the start of the comment to the next newline will be treated as a comment, including any diagram syntax Comments can be entered within a state diagram chart, which will be ignored by the parser. Comments need to be on their own line, and must be prefaced with `%%` (double percent signs). Any text after the start of the comment to the next newline will be treated as a comment, including any diagram syntax

View File

@ -1,14 +1,14 @@
const path = require('path'); const path = require('path');
module.exports = { module.exports = {
testEnvironment:"jsdom", testEnvironment: 'jsdom',
transform: { transform: {
'^.+\\.jsx?$': './transformer.js', '^.+\\.jsx?$': './transformer.js',
'^.+\\.jison$': path.resolve(__dirname, './jisonTransformer.js') '^.+\\.jison$': path.resolve(__dirname, './jisonTransformer.js'),
}, },
transformIgnorePatterns: ['/node_modules/(?!dagre-d3-renderer/lib).*\\.js'], transformIgnorePatterns: ['/node_modules/(?!dagre-d3-renderer/lib).*\\.js'],
moduleNameMapper: { moduleNameMapper: {
'\\.(css|scss)$': 'identity-obj-proxy' '\\.(css|scss)$': 'identity-obj-proxy',
}, },
moduleFileExtensions: ['js', 'json', 'jsx', 'ts', 'tsx', 'node', 'jison'] moduleFileExtensions: ['js', 'json', 'jsx', 'ts', 'tsx', 'node', 'jison'],
}; };

View File

@ -1,6 +1,6 @@
const { Generator } = require('jison') const { Generator } = require('jison');
const { getOptions } = require('loader-utils') const { getOptions } = require('loader-utils');
module.exports = function jisonLoader (source) { module.exports = function jisonLoader(source) {
return new Generator(source, getOptions(this)).generate() return new Generator(source, getOptions(this)).generate();
} };

View File

@ -3,7 +3,7 @@ const { Generator } = require('jison');
module.exports = { module.exports = {
process(source, filename, config, transformOptions) { process(source, filename, config, transformOptions) {
return new Generator(source, { return new Generator(source, {
'token-stack': true 'token-stack': true,
}).generate(); }).generate();
} },
}; };

View File

@ -1,6 +1,6 @@
{ {
"name": "mermaid", "name": "mermaid",
"version": "8.11.4", "version": "8.12.0",
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.", "description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
"main": "dist/mermaid.core.js", "main": "dist/mermaid.core.js",
"keywords": [ "keywords": [
@ -13,8 +13,8 @@
"git graph" "git graph"
], ],
"scripts": { "scripts": {
"build:development": "webpack --progress --colors", "build:development": "webpack --progress --color",
"build:production": "yarn build:development -p --config webpack.config.prod.babel.js", "build:production": "yarn build:development --mode production --config webpack.config.prod.babel.js",
"build": "yarn build:development && yarn build:production", "build": "yarn build:development && yarn build:production",
"postbuild": "documentation build src/mermaidAPI.js src/config.js src/defaultConfig.js --shallow -f md --markdown-toc false > docs/Setup.md", "postbuild": "documentation build src/mermaidAPI.js src/config.js src/defaultConfig.js --shallow -f md --markdown-toc false > docs/Setup.md",
"build:watch": "yarn build --watch", "build:watch": "yarn build --watch",
@ -24,7 +24,7 @@
"cypress": "percy exec -- cypress run", "cypress": "percy exec -- cypress run",
"e2e": "start-server-and-test dev http://localhost:9000/ cypress", "e2e": "start-server-and-test dev http://localhost:9000/ cypress",
"e2e-upd": "yarn lint && jest e2e -u --config e2e/jest.config.js", "e2e-upd": "yarn lint && jest e2e -u --config e2e/jest.config.js",
"dev": "webpack-dev-server --config webpack.config.e2e.js", "dev": "webpack serve --config webpack.config.e2e.js",
"test": "yarn lint && jest src/.*", "test": "yarn lint && jest src/.*",
"test:watch": "jest --watch src", "test:watch": "jest --watch src",
"prepublishOnly": "yarn build && yarn test", "prepublishOnly": "yarn build && yarn test",
@ -48,11 +48,10 @@
}, },
"dependencies": { "dependencies": {
"@braintree/sanitize-url": "^3.1.0", "@braintree/sanitize-url": "^3.1.0",
"@percy/migrate": "^0.10.0", "d3": "^7.0.0",
"d3": "^5.7.0",
"dagre": "^0.8.5", "dagre": "^0.8.5",
"dagre-d3": "^0.6.4", "dagre-d3": "^0.6.4",
"dompurify": "2.3.0", "dompurify": "2.3.1",
"graphlib": "^2.1.8", "graphlib": "^2.1.8",
"khroma": "^1.4.1", "khroma": "^1.4.1",
"moment-mini": "^2.24.0", "moment-mini": "^2.24.0",
@ -60,17 +59,17 @@
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.14.6", "@babel/core": "^7.14.6",
"@babel/eslint-parser": "^7.14.7",
"@babel/preset-env": "^7.14.7", "@babel/preset-env": "^7.14.7",
"@babel/register": "^7.14.5", "@babel/register": "^7.14.5",
"@percy/cli": "^1.0.0-beta.58", "@percy/cli": "^1.0.0-beta.58",
"@percy/cypress": "^3.1.0", "@percy/cypress": "^3.1.0",
"babel-core": "7.0.0-bridge.0", "@percy/migrate": "^0.11.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^27.0.6", "babel-jest": "^27.0.6",
"babel-loader": "^8.2.2", "babel-loader": "^8.2.2",
"coveralls": "^3.0.2", "coveralls": "^3.0.2",
"css-to-string-loader": "^0.1.3", "css-to-string-loader": "^0.1.3",
"cypress": "7.6.0", "cypress": "8.1.0",
"documentation": "13.2.0", "documentation": "13.2.0",
"eslint": "^7.30.0", "eslint": "^7.30.0",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
@ -83,21 +82,15 @@
"moment": "^2.23.0", "moment": "^2.23.0",
"prettier": "^2.3.2", "prettier": "^2.3.2",
"start-server-and-test": "^1.12.6", "start-server-and-test": "^1.12.6",
"terser-webpack-plugin": "^2.2.2", "terser-webpack-plugin": "^4.2.3",
"webpack": "^4.41.2", "webpack": "^4.41.2",
"webpack-bundle-analyzer": "^4.4.2", "webpack-cli": "^4.7.2",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "^3.4.1", "webpack-dev-server": "^3.4.1",
"webpack-node-externals": "^1.7.2" "webpack-node-externals": "^3.0.0"
}, },
"files": [ "files": [
"dist" "dist"
], ],
"yarn-upgrade-all": {
"ignore": [
"babel-core"
]
},
"sideEffects": [ "sideEffects": [
"**/*.css", "**/*.css",
"**/*.scss" "**/*.scss"

View File

@ -43,25 +43,27 @@ export const insertEdgeLabel = (elem, edge) => {
edge.width = bbox.width; edge.width = bbox.width;
edge.height = bbox.height; edge.height = bbox.height;
let fo;
if (edge.startLabelLeft) { if (edge.startLabelLeft) {
// Create the actual text element // Create the actual text element
const startLabelElement = createLabel(edge.startLabelLeft, edge.labelStyle); const startLabelElement = createLabel(edge.startLabelLeft, edge.labelStyle);
const startEdgeLabelLeft = elem.insert('g').attr('class', 'edgeTerminals'); const startEdgeLabelLeft = elem.insert('g').attr('class', 'edgeTerminals');
const inner = startEdgeLabelLeft.insert('g').attr('class', 'inner'); const inner = startEdgeLabelLeft.insert('g').attr('class', 'inner');
inner.node().appendChild(startLabelElement); fo = inner.node().appendChild(startLabelElement);
const slBox = startLabelElement.getBBox(); const slBox = startLabelElement.getBBox();
inner.attr('transform', 'translate(' + -slBox.width / 2 + ', ' + -slBox.height / 2 + ')'); inner.attr('transform', 'translate(' + -slBox.width / 2 + ', ' + -slBox.height / 2 + ')');
if (!terminalLabels[edge.id]) { if (!terminalLabels[edge.id]) {
terminalLabels[edge.id] = {}; terminalLabels[edge.id] = {};
} }
terminalLabels[edge.id].startLeft = startEdgeLabelLeft; terminalLabels[edge.id].startLeft = startEdgeLabelLeft;
setTerminalWidth(fo, edge.startLabelLeft);
} }
if (edge.startLabelRight) { if (edge.startLabelRight) {
// Create the actual text element // Create the actual text element
const startLabelElement = createLabel(edge.startLabelRight, edge.labelStyle); const startLabelElement = createLabel(edge.startLabelRight, edge.labelStyle);
const startEdgeLabelRight = elem.insert('g').attr('class', 'edgeTerminals'); const startEdgeLabelRight = elem.insert('g').attr('class', 'edgeTerminals');
const inner = startEdgeLabelRight.insert('g').attr('class', 'inner'); const inner = startEdgeLabelRight.insert('g').attr('class', 'inner');
startEdgeLabelRight.node().appendChild(startLabelElement); fo = startEdgeLabelRight.node().appendChild(startLabelElement);
inner.node().appendChild(startLabelElement); inner.node().appendChild(startLabelElement);
const slBox = startLabelElement.getBBox(); const slBox = startLabelElement.getBBox();
inner.attr('transform', 'translate(' + -slBox.width / 2 + ', ' + -slBox.height / 2 + ')'); inner.attr('transform', 'translate(' + -slBox.width / 2 + ', ' + -slBox.height / 2 + ')');
@ -70,21 +72,24 @@ export const insertEdgeLabel = (elem, edge) => {
terminalLabels[edge.id] = {}; terminalLabels[edge.id] = {};
} }
terminalLabels[edge.id].startRight = startEdgeLabelRight; terminalLabels[edge.id].startRight = startEdgeLabelRight;
setTerminalWidth(fo, edge.startLabelRight);
} }
if (edge.endLabelLeft) { if (edge.endLabelLeft) {
// Create the actual text element // Create the actual text element
const endLabelElement = createLabel(edge.endLabelLeft, edge.labelStyle); const endLabelElement = createLabel(edge.endLabelLeft, edge.labelStyle);
const endEdgeLabelLeft = elem.insert('g').attr('class', 'edgeTerminals'); const endEdgeLabelLeft = elem.insert('g').attr('class', 'edgeTerminals');
const inner = endEdgeLabelLeft.insert('g').attr('class', 'inner'); const inner = endEdgeLabelLeft.insert('g').attr('class', 'inner');
inner.node().appendChild(endLabelElement); fo = inner.node().appendChild(endLabelElement);
const slBox = endLabelElement.getBBox(); const slBox = endLabelElement.getBBox();
inner.attr('transform', 'translate(' + -slBox.width / 2 + ', ' + -slBox.height / 2 + ')'); inner.attr('transform', 'translate(' + -slBox.width / 2 + ', ' + -slBox.height / 2 + ')');
endEdgeLabelLeft.node().appendChild(endLabelElement); endEdgeLabelLeft.node().appendChild(endLabelElement);
if (!terminalLabels[edge.id]) { if (!terminalLabels[edge.id]) {
terminalLabels[edge.id] = {}; terminalLabels[edge.id] = {};
} }
terminalLabels[edge.id].endLeft = endEdgeLabelLeft; terminalLabels[edge.id].endLeft = endEdgeLabelLeft;
setTerminalWidth(fo, edge.endLabelLeft);
} }
if (edge.endLabelRight) { if (edge.endLabelRight) {
// Create the actual text element // Create the actual text element
@ -92,7 +97,7 @@ export const insertEdgeLabel = (elem, edge) => {
const endEdgeLabelRight = elem.insert('g').attr('class', 'edgeTerminals'); const endEdgeLabelRight = elem.insert('g').attr('class', 'edgeTerminals');
const inner = endEdgeLabelRight.insert('g').attr('class', 'inner'); const inner = endEdgeLabelRight.insert('g').attr('class', 'inner');
inner.node().appendChild(endLabelElement); fo = inner.node().appendChild(endLabelElement);
const slBox = endLabelElement.getBBox(); const slBox = endLabelElement.getBBox();
inner.attr('transform', 'translate(' + -slBox.width / 2 + ', ' + -slBox.height / 2 + ')'); inner.attr('transform', 'translate(' + -slBox.width / 2 + ', ' + -slBox.height / 2 + ')');
@ -101,9 +106,17 @@ export const insertEdgeLabel = (elem, edge) => {
terminalLabels[edge.id] = {}; terminalLabels[edge.id] = {};
} }
terminalLabels[edge.id].endRight = endEdgeLabelRight; terminalLabels[edge.id].endRight = endEdgeLabelRight;
setTerminalWidth(fo, edge.endLabelRight);
} }
}; };
function setTerminalWidth(fo, value) {
if (getConfig().flowchart.htmlLabels && fo) {
fo.style.width = value.length * 9 + 'px';
fo.style.height = '12px';
}
}
export const positionEdgeLabel = (edge, paths) => { export const positionEdgeLabel = (edge, paths) => {
log.info('Moving label abc78 ', edge.id, edge.label, edgeLabels[edge.id]); log.info('Moving label abc78 ', edge.id, edge.label, edgeLabels[edge.id]);
let path = paths.updatedPath ? paths.updatedPath : paths.originalPath; let path = paths.updatedPath ? paths.updatedPath : paths.originalPath;
@ -128,7 +141,7 @@ export const positionEdgeLabel = (edge, paths) => {
let y = edge.y; let y = edge.y;
if (path) { if (path) {
// debugger; // debugger;
const pos = utils.calcTerminalLabelPosition(0, 'start_left', path); const pos = utils.calcTerminalLabelPosition(edge.arrowTypeStart ? 10 : 0, 'start_left', path);
x = pos.x; x = pos.x;
y = pos.y; y = pos.y;
} }
@ -140,7 +153,11 @@ export const positionEdgeLabel = (edge, paths) => {
let y = edge.y; let y = edge.y;
if (path) { if (path) {
// debugger; // debugger;
const pos = utils.calcTerminalLabelPosition(0, 'start_right', path); const pos = utils.calcTerminalLabelPosition(
edge.arrowTypeStart ? 10 : 0,
'start_right',
path
);
x = pos.x; x = pos.x;
y = pos.y; y = pos.y;
} }
@ -152,7 +169,7 @@ export const positionEdgeLabel = (edge, paths) => {
let y = edge.y; let y = edge.y;
if (path) { if (path) {
// debugger; // debugger;
const pos = utils.calcTerminalLabelPosition(0, 'end_left', path); const pos = utils.calcTerminalLabelPosition(edge.arrowTypeEnd ? 10 : 0, 'end_left', path);
x = pos.x; x = pos.x;
y = pos.y; y = pos.y;
} }
@ -164,7 +181,7 @@ export const positionEdgeLabel = (edge, paths) => {
let y = edge.y; let y = edge.y;
if (path) { if (path) {
// debugger; // debugger;
const pos = utils.calcTerminalLabelPosition(0, 'end_right', path); const pos = utils.calcTerminalLabelPosition(edge.arrowTypeEnd ? 10 : 0, 'end_right', path);
x = pos.x; x = pos.x;
y = pos.y; y = pos.y;
} }

View File

@ -648,7 +648,11 @@ const class_box = (parent, node) => {
let classTitleString = node.classData.id; let classTitleString = node.classData.id;
if (node.classData.type !== undefined && node.classData.type !== '') { if (node.classData.type !== undefined && node.classData.type !== '') {
classTitleString += '<' + node.classData.type + '>'; if (getConfig().flowchart.htmlLabels) {
classTitleString += '&lt;' + node.classData.type + '&gt;';
} else {
classTitleString += '<' + node.classData.type + '>';
}
} }
const classTitleLabel = labelContainer const classTitleLabel = labelContainer
.node() .node()
@ -668,7 +672,10 @@ const class_box = (parent, node) => {
} }
const classAttributes = []; const classAttributes = [];
node.classData.members.forEach((str) => { node.classData.members.forEach((str) => {
const parsedText = parseMember(str).displayText; let parsedText = parseMember(str).displayText;
if (getConfig().flowchart.htmlLabels) {
parsedText = parsedText.replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
const lbl = labelContainer const lbl = labelContainer
.node() .node()
.appendChild(createLabel(parsedText, node.labelStyle, true, true)); .appendChild(createLabel(parsedText, node.labelStyle, true, true));
@ -691,10 +698,21 @@ const class_box = (parent, node) => {
const classMethods = []; const classMethods = [];
node.classData.methods.forEach((str) => { node.classData.methods.forEach((str) => {
const parsedText = parseMember(str).displayText; const parsedInfo = parseMember(str);
let displayText = parsedInfo.displayText;
if (getConfig().flowchart.htmlLabels) {
displayText = displayText.replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
const lbl = labelContainer const lbl = labelContainer
.node() .node()
.appendChild(createLabel(parsedText, node.labelStyle, true, true)); .appendChild(
createLabel(
displayText,
parsedInfo.cssStyle ? parsedInfo.cssStyle : node.labelStyle,
true,
true
)
);
let bbox = lbl.getBBox(); let bbox = lbl.getBBox();
if (evaluate(getConfig().flowchart.htmlLabels)) { if (evaluate(getConfig().flowchart.htmlLabels)) {
const div = lbl.children[0]; const div = lbl.children[0];

View File

@ -900,7 +900,7 @@ top of the chart
* *
* Default value: 'dagre-d3' * Default value: 'dagre-d3'
*/ */
defaultRenderer: 'dagre-d3', defaultRenderer: 'dagre-wrapper',
}, },
git: { git: {
arrowMarkerAbsolute: false, arrowMarkerAbsolute: false,

View File

@ -317,6 +317,12 @@ const setupToolTips = function (element) {
}; };
funs.push(setupToolTips); funs.push(setupToolTips);
let direction = 'TB';
const getDirection = () => direction;
const setDirection = (dir) => {
direction = dir;
};
export default { export default {
parseDirective, parseDirective,
getConfig: () => configApi.getConfig().class, getConfig: () => configApi.getConfig().class,
@ -328,6 +334,8 @@ export default {
addAnnotation, addAnnotation,
getRelations, getRelations,
addRelation, addRelation,
getDirection,
setDirection,
addMember, addMember,
addMembers, addMembers,
cleanupLabel, cleanupLabel,

View File

@ -207,7 +207,7 @@ export const addRelations = function (relations, g) {
edgeData.arrowheadStyle = 'fill: #333'; edgeData.arrowheadStyle = 'fill: #333';
edgeData.labelpos = 'c'; edgeData.labelpos = 'c';
if (getConfig().flowchart.htmlLabels && false) { // eslint-disable-line if (getConfig().flowchart.htmlLabels) { // eslint-disable-line
edgeData.labelType = 'html'; edgeData.labelType = 'html';
edgeData.label = '<span class="edgeLabel">' + edge.text + '</span>'; edgeData.label = '<span class="edgeLabel">' + edge.text + '</span>';
} else { } else {
@ -359,7 +359,7 @@ export const draw = function (text, id) {
// } // }
// Fetch the default direction, use TD if none was found // Fetch the default direction, use TD if none was found
let dir = 'TD'; //let dir = 'TD';
const conf = getConfig().flowchart; const conf = getConfig().flowchart;
log.info('config:', conf); log.info('config:', conf);
@ -372,7 +372,7 @@ export const draw = function (text, id) {
compound: true, compound: true,
}) })
.setGraph({ .setGraph({
rankdir: dir, rankdir: classDb.getDirection(),
nodesep: nodeSpacing, nodesep: nodeSpacing,
ranksep: rankSpacing, ranksep: rankSpacing,
marginx: 8, marginx: 8,
@ -457,7 +457,7 @@ export const draw = function (text, id) {
rect.setAttribute('ry', 0); rect.setAttribute('ry', 0);
rect.setAttribute('width', dim.width); rect.setAttribute('width', dim.width);
rect.setAttribute('height', dim.height); rect.setAttribute('height', dim.height);
rect.setAttribute('style', 'fill:#e8e8e8;'); // rect.setAttribute('style', 'fill:#e8e8e8;');
label.insertBefore(rect, label.firstChild); label.insertBefore(rect, label.firstChild);
} }

View File

@ -19,6 +19,10 @@
%% %%
\%\%\{ { this.begin('open_directive'); return 'open_directive'; } \%\%\{ { this.begin('open_directive'); return 'open_directive'; }
.*direction\s+TB[^\n]* return 'direction_tb';
.*direction\s+BT[^\n]* return 'direction_bt';
.*direction\s+RL[^\n]* return 'direction_rl';
.*direction\s+LR[^\n]* return 'direction_lr';
<open_directive>((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; } <open_directive>((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; }
<type_directive>":" { this.popState(); this.begin('arg_directive'); return ':'; } <type_directive>":" { this.popState(); this.begin('arg_directive'); return ':'; }
<type_directive,arg_directive>\}\%\% { this.popState(); this.popState(); return 'close_directive'; } <type_directive,arg_directive>\}\%\% { this.popState(); this.popState(); return 'close_directive'; }
@ -180,9 +184,21 @@ Function arguments are optional: 'call <callback_name>()' simply executes 'callb
start start
: mermaidDoc : mermaidDoc
| direction
| directive start | directive start
; ;
direction
: direction_tb
{ yy.setDirection('TB');}
| direction_bt
{ yy.setDirection('BT');}
| direction_rl
{ yy.setDirection('RL');}
| direction_lr
{ yy.setDirection('LR');}
;
mermaidDoc mermaidDoc
: graphConfig : graphConfig
; ;
@ -235,6 +251,7 @@ statement
| clickStatement | clickStatement
| cssClassStatement | cssClassStatement
| directive | directive
| direction
; ;
classStatement classStatement

View File

@ -12,6 +12,19 @@ const getStyles = (options) =>
} }
.nodeLabel, .edgeLabel {
color: ${options.classText};
}
.edgeLabel .label rect {
fill: ${options.mainBkg};
}
.label text {
fill: ${options.classText};
}
.edgeLabel .label span {
background: ${options.mainBkg};
}
.classTitle { .classTitle {
font-weight: bolder; font-weight: bolder;
} }

View File

@ -38,7 +38,7 @@ const getStyles = (options) =>
.edgePath .path { .edgePath .path {
stroke: ${options.lineColor}; stroke: ${options.lineColor};
stroke-width: 1.5px; stroke-width: 2.0px;
} }
.flowchart-link { .flowchart-link {

View File

@ -1,7 +1,7 @@
/** /**
* Created by AshishJ on 11-09-2019. * Created by AshishJ on 11-09-2019.
*/ */
import { select, scaleOrdinal, pie as d3pie, entries, arc } from 'd3'; import { select, scaleOrdinal, pie as d3pie, arc } from 'd3';
import pieData from './pieDb'; import pieData from './pieDb';
import pieParser from './parser/pie'; import pieParser from './parser/pie';
import { log } from '../../logger'; import { log } from '../../logger';
@ -81,13 +81,13 @@ export const draw = (txt, id) => {
]; ];
// Set the color scale // Set the color scale
var color = scaleOrdinal().domain(data).range(myGeneratedColors); var color = scaleOrdinal().range(myGeneratedColors);
// Compute the position of each group on the pie: // Compute the position of each group on the pie:
var pie = d3pie().value(function (d) { var pie = d3pie().value(function (d) {
return d.value; return d[1];
}); });
var dataReady = pie(entries(data)); var dataReady = pie(Object.entries(data));
// Shape helper to build arcs: // Shape helper to build arcs:
var arcGenerator = arc().innerRadius(0).outerRadius(radius); var arcGenerator = arc().innerRadius(0).outerRadius(radius);
@ -100,7 +100,7 @@ export const draw = (txt, id) => {
.append('path') .append('path')
.attr('d', arcGenerator) .attr('d', arcGenerator)
.attr('fill', function (d) { .attr('fill', function (d) {
return color(d.data.key); return color(d.data[0]);
}) })
.attr('class', 'pieCircle'); .attr('class', 'pieCircle');
@ -108,11 +108,11 @@ export const draw = (txt, id) => {
// Use the centroid method to get the best coordinates. // Use the centroid method to get the best coordinates.
svg svg
.selectAll('mySlices') .selectAll('mySlices')
.data(dataReady.filter((value) => value.data.value !== 0)) .data(dataReady)
.enter() .enter()
.append('text') .append('text')
.text(function (d) { .text(function (d) {
return ((d.data.value / sum) * 100).toFixed(0) + '%'; return ((d.data[1] / sum) * 100).toFixed(0) + '%';
}) })
.attr('transform', function (d) { .attr('transform', function (d) {
return 'translate(' + arcGenerator.centroid(d) + ')'; return 'translate(' + arcGenerator.centroid(d) + ')';
@ -150,15 +150,15 @@ export const draw = (txt, id) => {
.style('stroke', color); .style('stroke', color);
legend legend
.data(dataReady.filter((value) => value.data.value !== 0)) .data(dataReady)
.append('text') .append('text')
.attr('x', legendRectSize + legendSpacing) .attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing) .attr('y', legendRectSize - legendSpacing)
.text(function (d) { .text(function (d) {
if (parser.yy.getShowData() || conf.showData || conf.pie.showData) { if (parser.yy.getShowData() || conf.showData || conf.pie.showData) {
return d.data.key + ' [' + d.data.value + ']'; return d.data[0] + ' [' + d.data[1] + ']';
} else { } else {
return d.data.key; return d.data[0];
} }
}); });
} catch (e) { } catch (e) {

View File

@ -410,7 +410,7 @@ const calcTerminalLabelPosition = (terminalMarkerSize, position, _points) => {
}); });
// Traverse only 25 total distance along points to find cardinality point // Traverse only 25 total distance along points to find cardinality point
const distanceToCardinalityPoint = 25; const distanceToCardinalityPoint = 25 + terminalMarkerSize;
let remainingDistance = distanceToCardinalityPoint; let remainingDistance = distanceToCardinalityPoint;
let center; let center;
@ -437,7 +437,7 @@ const calcTerminalLabelPosition = (terminalMarkerSize, position, _points) => {
prevPoint = point; prevPoint = point;
}); });
// if relation is present (Arrows will be added), change cardinality point off-set distance (d) // if relation is present (Arrows will be added), change cardinality point off-set distance (d)
let d = 10; let d = 10 + terminalMarkerSize * 0.5;
//Calculate Angle for x and y axis //Calculate Angle for x and y axis
let angle = Math.atan2(points[0].y - center.y, points[0].x - center.x); let angle = Math.atan2(points[0].y - center.y, points[0].x - center.x);

View File

@ -1,11 +1,11 @@
import nodeExternals from 'webpack-node-externals' import nodeExternals from 'webpack-node-externals';
import { jsConfig } from './webpack.config.base' import { jsConfig } from './webpack.config.base';
const config = jsConfig() const config = jsConfig();
const coreConfig = jsConfig() const coreConfig = jsConfig();
coreConfig.externals = [nodeExternals()] coreConfig.externals = [nodeExternals()];
coreConfig.output.filename = '[name].core.js' coreConfig.output.filename = '[name].core.js';
export default [config, coreConfig] export default [config, coreConfig];

View File

@ -1,10 +1,9 @@
import path from 'path'; import path from 'path';
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const amdRule = { const amdRule = {
parser: { parser: {
amd: false // https://github.com/lodash/lodash/issues/3052 amd: false, // https://github.com/lodash/lodash/issues/3052
} },
}; };
const jisonRule = { const jisonRule = {
@ -12,25 +11,25 @@ const jisonRule = {
use: { use: {
loader: path.resolve(__dirname, './jisonLoader'), loader: path.resolve(__dirname, './jisonLoader'),
options: { options: {
'token-stack': true 'token-stack': true,
} },
} },
}; };
const jsRule = { const jsRule = {
test: /\.js$/, test: /\.js$/,
include: [ include: [
path.resolve(__dirname, './src'), path.resolve(__dirname, './src'),
path.resolve(__dirname, './node_modules/dagre-d3-renderer/lib') path.resolve(__dirname, './node_modules/dagre-d3-renderer/lib'),
], ],
use: { use: {
loader: 'babel-loader' loader: 'babel-loader',
} },
}; };
const scssRule = { const scssRule = {
// load scss to string // load scss to string
test: /\.scss$/, test: /\.scss$/,
use: [{ loader: 'css-to-string-loader' }, { loader: 'css-loader' }, { loader: 'sass-loader' }] use: [{ loader: 'css-to-string-loader' }, { loader: 'css-loader' }, { loader: 'sass-loader' }],
}; };
export const jsConfig = () => { export const jsConfig = () => {
@ -38,13 +37,13 @@ export const jsConfig = () => {
mode: 'development', mode: 'development',
target: 'web', target: 'web',
entry: { entry: {
mermaid: './src/mermaid.js' mermaid: './src/mermaid.js',
}, },
resolve: { resolve: {
extensions: ['.wasm', '.mjs', '.js', '.json', '.jison'] extensions: ['.wasm', '.mjs', '.js', '.json', '.jison'],
}, },
node: { node: {
fs: 'empty' // jison generated code requires 'fs' fs: 'empty', // jison generated code requires 'fs'
}, },
output: { output: {
path: path.join(__dirname, './dist/'), path: path.join(__dirname, './dist/'),
@ -52,12 +51,11 @@ export const jsConfig = () => {
library: 'mermaid', library: 'mermaid',
libraryTarget: 'umd', libraryTarget: 'umd',
libraryExport: 'default', libraryExport: 'default',
globalObject: 'typeof self !== "undefined" ? self : this' globalObject: 'typeof self !== "undefined" ? self : this',
}, },
module: { module: {
rules: [amdRule, jsRule, scssRule, jisonRule] rules: [amdRule, jsRule, scssRule, jisonRule],
}, },
// plugins: [new BundleAnalyzerPlugin()], devtool: 'source-map',
devtool: 'source-map'
}; };
}; };

View File

@ -4,8 +4,8 @@ const jsRule = {
test: /\.js$/, test: /\.js$/,
exclude: /node_modules/, exclude: /node_modules/,
use: { use: {
loader: 'babel-loader' loader: 'babel-loader',
} },
}; };
const jisonRule = { const jisonRule = {
@ -13,20 +13,20 @@ const jisonRule = {
use: { use: {
loader: path.resolve(__dirname, './jisonLoader'), loader: path.resolve(__dirname, './jisonLoader'),
options: { options: {
'token-stack': true 'token-stack': true,
} },
} },
}; };
const amdRule = { const amdRule = {
parser: { parser: {
amd: false // https://github.com/lodash/lodash/issues/3052 amd: false, // https://github.com/lodash/lodash/issues/3052
} },
}; };
const scssRule = { const scssRule = {
// load scss to string // load scss to string
test: /\.scss$/, test: /\.scss$/,
use: [{ loader: 'css-to-string-loader' }, { loader: 'css-loader' }, { loader: 'sass-loader' }] use: [{ loader: 'css-to-string-loader' }, { loader: 'css-loader' }, { loader: 'sass-loader' }],
}; };
module.exports = { module.exports = {
@ -35,31 +35,31 @@ module.exports = {
entry: { entry: {
mermaid: './src/mermaid.js', mermaid: './src/mermaid.js',
e2e: './cypress/platform/viewer.js', e2e: './cypress/platform/viewer.js',
'bundle-test': './cypress/platform/bundle-test.js' 'bundle-test': './cypress/platform/bundle-test.js',
}, },
resolve: { resolve: {
extensions: ['.wasm', '.mjs', '.js', '.json', '.jison'] extensions: ['.wasm', '.mjs', '.js', '.json', '.jison'],
}, },
node: { node: {
fs: 'empty' // jison generated code requires 'fs' fs: 'empty', // jison generated code requires 'fs'
}, },
output: { output: {
path: path.join(__dirname, './dist/'), path: path.join(__dirname, './dist/'),
filename: '[name].js', filename: '[name].js',
library: 'mermaid', library: 'mermaid',
libraryTarget: 'umd', libraryTarget: 'umd',
libraryExport: 'default' libraryExport: 'default',
}, },
devServer: { devServer: {
contentBase: [path.join(__dirname, 'cypress', 'platform'), path.join(__dirname, 'dist')], contentBase: [path.join(__dirname, 'cypress', 'platform'), path.join(__dirname, 'dist')],
compress: true, compress: true,
port: 9000 port: 9000,
}, },
module: { module: {
rules: [amdRule, jsRule, scssRule, jisonRule] rules: [amdRule, jsRule, scssRule, jisonRule],
}, },
externals: { externals: {
mermaid: 'mermaid' mermaid: 'mermaid',
}, },
devtool: 'source-map' devtool: 'source-map',
}; };

View File

@ -1,7 +1,7 @@
import { jsConfig } from './webpack.config.base' import { jsConfig } from './webpack.config.base';
const minConfig = jsConfig() const minConfig = jsConfig();
minConfig.mode = 'production' minConfig.mode = 'production';
minConfig.output.filename = '[name].min.js' minConfig.output.filename = '[name].min.js';
export default [minConfig] export default [minConfig];

1383
yarn.lock

File diff suppressed because it is too large Load Diff