Merge branch 'develop' into feature/2249_sequence_diagram_popup_menus

This commit is contained in:
E Jenkins 2021-08-27 15:02:11 -07:00 committed by GitHub
commit ce6d8576ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
180 changed files with 80046 additions and 14515 deletions

View File

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

View File

@ -23,6 +23,9 @@ A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Code Sample**
If applicable, add the code sample or a link to the [live editor](https://mermaid-js.github.io/mermaid-live-editor).
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]

12
.github/dependabot.yml vendored Normal file
View File

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

View File

@ -1,3 +1,4 @@
'Type: Bug / Error': 'bug/*'
'Type: Enhancement': 'feature/*'
'Type: Other': 'other/*'
'Type: Dependabot': 'dependabot/*'

View File

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

View File

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

View File

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

View File

@ -8,6 +8,6 @@ jobs:
triage:
runs-on: ubuntu-latest
steps:
- uses: Dunning-Kruger/lock-issues@v1
- uses: Dunning-Kruger/lock-issues@v1.1
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"

View File

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

View File

@ -9,11 +9,11 @@ jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v1
uses: actions/setup-node@v2
with:
node-version: 10.x
node-version: 16.x
- name: Install Yarn
run: npm i yarn --global
@ -25,7 +25,7 @@ jobs:
- name: Publish
run: |
PREVIEW_VERSION=$(git rev-list --count --first-parent HEAD)
PREVIEW_VERSION=8
VERSION=$(echo ${{github.ref}} | tail -c +20)-preview.$PREVIEW_VERSION
echo $VERSION
npm version --no-git-tag-version --allow-same-version $VERSION

View File

@ -8,13 +8,13 @@ jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v2.3.4
- uses: fregante/setup-git-user@v1
- name: Setup Node.js
uses: actions/setup-node@v1
uses: actions/setup-node@v2
with:
node-version: 10.x
node-version: 16.x
- name: Install Yarn
run: npm i yarn --global

3
.percy.old.yml Normal file
View File

@ -0,0 +1,3 @@
version: 1
snapshot:
widths: [1280]

View File

@ -1,3 +1,6 @@
version: 1
version: 2
snapshot:
widths: [1280]
widths:
- 1280
discovery:
disable-cache: true

View File

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

View File

@ -1,16 +1,12 @@
# mermaid [![Build Status](https://travis-ci.org/mermaid-js/mermaid.svg?branch=master)](https://travis-ci.org/mermaid-js/mermaid) [![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.com/package/mermaid) [![Coverage Status](https://coveralls.io/repos/github/mermaid-js/mermaid/badge.svg?branch=master)](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) [![This project is using Percy.io for visual regression testing.](https://percy.io/static/images/percy-badge.svg)](https://percy.io/Mermaid/mermaid)
<p align="center">
<a href="https://www.buymeacoffee.com/knsv" rel="nofollow">
<img src="https://user-images.githubusercontent.com/30767528/63641973-9d301680-c6b7-11e9-9d29-2ad1da50fdce.png" style="max-width:100%;" />
</a>
</p>
![banner](./img/header.png)
:trophy: **Mermaid was nominated and won the [JS Open Source Awards (2019)](https://osawards.com/javascript/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 🙏**
**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
@ -24,7 +20,7 @@ But not having diagrams or docs ruins productivity and hurts organizational lear
Mermaid addresses this problem by cutting the time, effort and tooling that is required to create modifiable diagrams and charts, for smarter and more reusable content.
The text definitions for Mermaid 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 to be spent on documenting, as a separate and laborious task. <br/>
Even non-programmers can create diagrams through the [Mermaid Live Editor](https://github.com/mermaid-js/mermaid-live-editor).<br/>
Even non-programmers can create diagrams through the [Mermaid Live Editor](https://mermaid-js.github.io/mermaid-live-editor/).<br/>
[Tutorials](./docs/Tutorials.md) has video tutorials.
Use Mermaid with your favorite applications, check out the list of [Integrations and Usages of Mermaid](./docs/integrations.md).

View File

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

View File

@ -178,7 +178,8 @@ describe('Interaction', () => {
.find('g#flowchart-Function-2')
.click();
cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow');
cy.get('.created-by-click').should('not.exist');
// cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow');
});
it('should handle a click on a node with a bound function where the node starts with a number', () => {
const url = 'http://localhost:9000/click_security_strict.html';
@ -188,7 +189,8 @@ describe('Interaction', () => {
.find('g[id="flowchart-1Function-6"]')
.click();
cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow');
// cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow');
cy.get('.created-by-click').should('not.exist');
});
it('should handle a click on a node with a bound url', () => {
const url = 'http://localhost:9000/click_security_strict.html';
@ -247,7 +249,8 @@ describe('Interaction', () => {
.find('rect#cl2')
.click({ force: true });
cy.get('.created-by-gant-click').should('not.have.text', 'Clicked By Gant cl2');
// cy.get('.created-by-gant-click').should('not.have.text', 'Clicked By Gant cl2');
cy.get('.created-by-gant-click').should('not.exist')
});
it('should handle a click on a task with a bound function', () => {
const url = 'http://localhost:9000/click_security_strict.html';
@ -257,7 +260,8 @@ describe('Interaction', () => {
.find('text#cl2-text')
.click({ force: true });
cy.get('.created-by-gant-click').should('not.have.text', 'Clicked By Gant cl2');
// cy.get('.created-by-gant-click').should('not.have.text', 'Clicked By Gant cl2');
cy.get('.created-by-gant-click').should('not.exist')
});
});
@ -270,7 +274,8 @@ describe('Interaction', () => {
.find('g#flowchart-Function-2')
.click();
cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow');
// cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow');
cy.get('.created-by-click').should('not.exist');
});
it('should handle a click on a node with a bound function where the node starts with a number', () => {
const url = 'http://localhost:9000/click_security_other.html';
@ -280,7 +285,8 @@ describe('Interaction', () => {
.find('g[id="flowchart-1Function-6"]')
.click();
cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow');
cy.get('.created-by-click').should('not.exist');
cy.get('.created-by-click').should('not.exist');
});
it('should handle a click on a node with a bound url', () => {
const url = 'http://localhost:9000/click_security_other.html';
@ -303,7 +309,7 @@ describe('Interaction', () => {
.find('rect#cl2')
.click({ force: true });
cy.get('.created-by-gant-click').should('not.have.text', 'Clicked By Gant cl2');
cy.get('.created-by-gant-click').should('not.exist');
});
it('should handle a click on a task with a bound function', () => {
const url = 'http://localhost:9000/click_security_other.html';
@ -313,7 +319,7 @@ describe('Interaction', () => {
.find('text#cl2-text')
.click({ force: true });
cy.get('.created-by-gant-click').should('not.have.text', 'Clicked By Gant cl2');
cy.get('.created-by-gant-click').should('not.exist');
});
});
});

View File

@ -16,6 +16,6 @@ describe('Sequencediagram', () => {
.find('svg')
.should('have.length', 1);
cy.get('.label > g > foreignobject > div').should('not.contain.text', '<b>');
cy.get('g.label > foreignobject > div').should('not.contain.text', '<b>');
});
});

View File

@ -53,5 +53,20 @@ describe('XSS', () => {
cy.wait(1000);
cy.get('#the-malware').should('not.exist');
})
it('should not allow maniplulating htmlLabels into a false positive', () => {
cy.visit('http://localhost:9000/xss4.html');
cy.wait(1000);
cy.get('#the-malware').should('not.exist');
})
it('should not allow maniplulating antiscript to run javascript', () => {
cy.visit('http://localhost:9000/xss5.html');
cy.wait(1000);
cy.get('#the-malware').should('not.exist');
})
it('should not allow maniplulating antiscript to run javascript using onerror', () => {
cy.visit('http://localhost:9000/xss6.html');
cy.wait(1000);
cy.get('#the-malware').should('not.exist');
})
})

View File

@ -370,4 +370,100 @@ describe('Class diagram V2', () => {
);
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 */
import { imgSnapshotTest, renderGraph } from '../../helpers/util';
describe('Class diagram', () => {
it('1: should render a simple class diagram', () => {
imgSnapshotTest(
`
classDiagram
Class01 <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 *-- Class04
Class05 o-- Class06
Class07 .. Class08
Class09 --> C2 : Where am i?
Class09 --* C3
Class09 --|> Class07
Class12 <|.. Class08
Class11 ..>Class12
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class01 : -int privateChimp
Class01 : +int publicGorilla
Class01 : #int protectedMarmoset
Class08 <--> C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
{logLevel : 1}
);
cy.get('svg');
});
it('2: should render a simple class diagrams with cardinality', () => {
imgSnapshotTest(
`
classDiagram
Class01 "1" <|--|> "*" AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 "1" *-- "*" Class04
Class05 "1" o-- "many" Class06
Class07 "1" .. "*" Class08
Class09 "1" --> "*" C2 : Where am i?
Class09 "*" --* "*" C3
Class09 "1" --|> "1" Class07
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 "1" <--> "*" C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
{}
);
cy.get('svg');
});
it('3: should render a simple class diagram with different visibilities', () => {
imgSnapshotTest(
`
classDiagram
Class01 <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class01 : -privateMethod()
Class01 : +publicMethod()
Class01 : #protectedMethod()
Class01 : -int privateChimp
Class01 : +int publicGorilla
Class01 : #int protectedMarmoset
`,
{}
);
cy.get('svg');
});
it('4: should render a simple class diagram with comments', () => {
imgSnapshotTest(
`
classDiagram
%% this is a comment
Class01 <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 *-- Class04
Class05 o-- Class06
Class07 .. Class08
Class09 --> C2 : Where am i?
Class09 --* C3
Class09 --|> Class07
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 <--> C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
{}
);
cy.get('svg');
});
it('5: should render a simple class diagram with abstract method', () => {
imgSnapshotTest(
`
classDiagram
Class01 <|-- AveryLongClass : Cool
Class01 : someMethod()*
`,
{}
);
cy.get('svg');
});
it('6: should render a simple class diagram with static method', () => {
imgSnapshotTest(
`
classDiagram
Class01 <|-- AveryLongClass : Cool
Class01 : someMethod()$
`,
{}
);
cy.get('svg');
});
it('7: should render a simple class diagram with Generic class', () => {
imgSnapshotTest(
`
classDiagram
class Class01~T~
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 <--> C2: Cool label
class Class10~T~ {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
{}
);
cy.get('svg');
});
it('8: should render a simple class diagram with Generic class and relations', () => {
imgSnapshotTest(
`
classDiagram
Class01~T~ <|-- AveryLongClass : Cool
Class03~T~ *-- Class04~T~
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 <--> C2: Cool label
class Class10~T~ {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
{}
);
cy.get('svg');
});
it('9: should render a simple class diagram with clickable link', () => {
imgSnapshotTest(
`
classDiagram
Class01~T~ <|-- AveryLongClass : Cool
Class03~T~ *-- Class04~T~
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 <--> C2: Cool label
class Class10~T~ {
&lt;&lt;service&gt;&gt;
int id
test()
}
link Class01 "google.com" "A Tooltip"
`,
{}
);
cy.get('svg');
});
it('10: should render a simple class diagram with clickable callback', () => {
imgSnapshotTest(
`
classDiagram
Class01~T~ <|-- AveryLongClass : Cool
Class03~T~ *-- Class04~T~
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 <--> C2: Cool label
class Class10~T~ {
&lt;&lt;service&gt;&gt;
int id
test()
}
callback Class01 "functionCall" "A Tooltip"
`,
{}
);
cy.get('svg');
});
it('11: should render a simple class diagram with return type on method', () => {
imgSnapshotTest(
`
classDiagram
class Class10~T~ {
int[] id
test(int[] ids) bool
testArray() bool[]
}
`,
{}
);
cy.get('svg');
});
it('12: should render a simple class diagram with generic types', () => {
imgSnapshotTest(
`
classDiagram
class Class10~T~ {
int[] id
List~int~ ids
test(List~int~ ids) List~bool~
testArray() bool[]
}
`,
{}
);
cy.get('svg');
});
it('13: should render a simple class diagram with css classes applied', () => {
imgSnapshotTest(
`
classDiagram
class Class10 {
int[] id
List~int~ ids
test(List~int~ ids) List~bool~
testArray() bool[]
}
cssClass "Class10" exClass
`,
{}
);
cy.get('svg');
});
it('14: should render a simple class diagram with css classes applied directly', () => {
imgSnapshotTest(
`
classDiagram
class Class10:::exClass {
int[] id
List~int~ ids
test(List~int~ ids) List~bool~
testArray() bool[]
}
`,
{}
);
cy.get('svg');
});
it('15: should render a simple class diagram with css classes applied two multiple classes', () => {
imgSnapshotTest(
`
classDiagram
class Class10
class Class20
cssClass "Class10, class20" exClass
`,
{}
);
cy.get('svg');
});
it('16: should render multiple class diagrams', () => {
imgSnapshotTest(
[
`
classDiagram
Class01 "1" <|--|> "*" AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 "1" *-- "*" Class04
Class05 "1" o-- "many" Class06
Class07 "1" .. "*" Class08
Class09 "1" --> "*" C2 : Where am i?
Class09 "*" --* "*" C3
Class09 "1" --|> "1" Class07
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 "1" <--> "*" C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
`
classDiagram
Class01 "1" <|--|> "*" AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 "1" *-- "*" Class04
Class05 "1" o-- "many" Class06
Class07 "1" .. "*" Class08
Class09 "1" --> "*" C2 : Where am i?
Class09 "*" --* "*" C3
Class09 "1" --|> "1" Class07
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 "1" <--> "*" C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
],
{}
);
cy.get('svg');
});
it('17: should render a class diagram when useMaxWidth is true (default)', () => {
renderGraph(
`
classDiagram
Class01 <|-- AveryLongClass : Cool
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class01 : -int privateChimp
Class01 : +int publicGorilla
Class01 : #int protectedMarmoset
`,
{ class: { useMaxWidth: true } }
);
cy.get('svg')
.should((svg) => {
expect(svg).to.have.attr('width', '100%');
expect(svg).to.have.attr('height', '218');
const style = svg.attr('style');
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(160 * .95, 160 * 1.05);
});
});
it('18: should render a class diagram when useMaxWidth is false', () => {
renderGraph(
`
classDiagram
Class01 <|-- AveryLongClass : Cool
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class01 : -int privateChimp
Class01 : +int publicGorilla
Class01 : #int protectedMarmoset
`,
{ class: { useMaxWidth: false } }
);
cy.get('svg')
.should((svg) => {
const width = parseFloat(svg.attr('width'));
// use within because the absolute value can be slightly different depending on the environment ±5%
expect(width).to.be.within(160 * .95, 160 * 1.05);
expect(svg).to.have.attr('height', '218');
expect(svg).to.not.have.attr('style');
});
});
});
/* eslint-env jest */
import { imgSnapshotTest, renderGraph } from '../../helpers/util';
describe('Class diagram', () => {
it('1: should render a simple class diagram', () => {
imgSnapshotTest(
`
classDiagram
Class01 <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 *-- Class04
Class05 o-- Class06
Class07 .. Class08
Class09 --> C2 : Where am i?
Class09 --* C3
Class09 --|> Class07
Class12 <|.. Class08
Class11 ..>Class12
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class01 : -int privateChimp
Class01 : +int publicGorilla
Class01 : #int protectedMarmoset
Class08 <--> C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
{logLevel : 1}
);
cy.get('svg');
});
it('2: should render a simple class diagrams with cardinality', () => {
imgSnapshotTest(
`
classDiagram
Class01 "1" <|--|> "*" AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 "1" *-- "*" Class04
Class05 "1" o-- "many" Class06
Class07 "1" .. "*" Class08
Class09 "1" --> "*" C2 : Where am i?
Class09 "*" --* "*" C3
Class09 "1" --|> "1" Class07
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 "1" <--> "*" C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
{}
);
cy.get('svg');
});
it('3: should render a simple class diagram with different visibilities', () => {
imgSnapshotTest(
`
classDiagram
Class01 <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class01 : -privateMethod()
Class01 : +publicMethod()
Class01 : #protectedMethod()
Class01 : -int privateChimp
Class01 : +int publicGorilla
Class01 : #int protectedMarmoset
`,
{}
);
cy.get('svg');
});
it('4: should render a simple class diagram with comments', () => {
imgSnapshotTest(
`
classDiagram
%% this is a comment
Class01 <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 *-- Class04
Class05 o-- Class06
Class07 .. Class08
Class09 --> C2 : Where am i?
Class09 --* C3
Class09 --|> Class07
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 <--> C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
{}
);
cy.get('svg');
});
it('5: should render a simple class diagram with abstract method', () => {
imgSnapshotTest(
`
classDiagram
Class01 <|-- AveryLongClass : Cool
Class01 : someMethod()*
`,
{}
);
cy.get('svg');
});
it('6: should render a simple class diagram with static method', () => {
imgSnapshotTest(
`
classDiagram
Class01 <|-- AveryLongClass : Cool
Class01 : someMethod()$
`,
{}
);
cy.get('svg');
});
it('7: should render a simple class diagram with Generic class', () => {
imgSnapshotTest(
`
classDiagram
class Class01~T~
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 <--> C2: Cool label
class Class10~T~ {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
{}
);
cy.get('svg');
});
it('8: should render a simple class diagram with Generic class and relations', () => {
imgSnapshotTest(
`
classDiagram
Class01~T~ <|-- AveryLongClass : Cool
Class03~T~ *-- Class04~T~
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 <--> C2: Cool label
class Class10~T~ {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
{}
);
cy.get('svg');
});
it('9: should render a simple class diagram with clickable link', () => {
imgSnapshotTest(
`
classDiagram
Class01~T~ <|-- AveryLongClass : Cool
Class03~T~ *-- Class04~T~
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 <--> C2: Cool label
class Class10~T~ {
&lt;&lt;service&gt;&gt;
int id
test()
}
link Class01 "google.com" "A Tooltip"
`,
{}
);
cy.get('svg');
});
it('10: should render a simple class diagram with clickable callback', () => {
imgSnapshotTest(
`
classDiagram
Class01~T~ <|-- AveryLongClass : Cool
Class03~T~ *-- Class04~T~
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 <--> C2: Cool label
class Class10~T~ {
&lt;&lt;service&gt;&gt;
int id
test()
}
callback Class01 "functionCall" "A Tooltip"
`,
{}
);
cy.get('svg');
});
it('11: should render a simple class diagram with return type on method', () => {
imgSnapshotTest(
`
classDiagram
class Class10~T~ {
int[] id
test(int[] ids) bool
testArray() bool[]
}
`,
{}
);
cy.get('svg');
});
it('12: should render a simple class diagram with generic types', () => {
imgSnapshotTest(
`
classDiagram
class Class10~T~ {
int[] id
List~int~ ids
test(List~int~ ids) List~bool~
testArray() bool[]
}
`,
{}
);
cy.get('svg');
});
it('13: should render a simple class diagram with css classes applied', () => {
imgSnapshotTest(
`
classDiagram
class Class10 {
int[] id
List~int~ ids
test(List~int~ ids) List~bool~
testArray() bool[]
}
class Class10:::exClass2
`,
{}
);
cy.get('svg');
});
it('14: should render a simple class diagram with css classes applied directly', () => {
imgSnapshotTest(
`
classDiagram
class Class10:::exClass2 {
int[] id
List~int~ ids
test(List~int~ ids) List~bool~
testArray() bool[]
}
`,
{}
);
cy.get('svg');
});
it('15: should render a simple class diagram with css classes applied two multiple classes', () => {
imgSnapshotTest(
`
classDiagram
class Class10
class Class20
cssClass "Class10, Class20" exClass2
class Class20:::exClass2
`,
{}
);
cy.get('svg');
});
it('16: should render multiple class diagrams', () => {
imgSnapshotTest(
[
`
classDiagram
Class01 "1" <|--|> "*" AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 "1" *-- "*" Class04
Class05 "1" o-- "many" Class06
Class07 "1" .. "*" Class08
Class09 "1" --> "*" C2 : Where am i?
Class09 "*" --* "*" C3
Class09 "1" --|> "1" Class07
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 "1" <--> "*" C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
`
classDiagram
Class01 "1" <|--|> "*" AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 "1" *-- "*" Class04
Class05 "1" o-- "many" Class06
Class07 "1" .. "*" Class08
Class09 "1" --> "*" C2 : Where am i?
Class09 "*" --* "*" C3
Class09 "1" --|> "1" Class07
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 "1" <--> "*" C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
],
{}
);
cy.get('svg');
});
// it('17: should render a class diagram when useMaxWidth is true (default)', () => {
// renderGraph(
// `
// classDiagram
// Class01 <|-- AveryLongClass : Cool
// Class01 : size()
// Class01 : int chimp
// Class01 : int gorilla
// Class01 : -int privateChimp
// Class01 : +int publicGorilla
// Class01 : #int protectedMarmoset
// `,
// { class: { useMaxWidth: true } }
// );
// cy.get('svg')
// .should((svg) => {
// expect(svg).to.have.attr('width', '100%');
// const height = parseFloat(svg.attr('height'));
// expect(height).to.be.within(332, 333);
// // expect(svg).to.have.attr('height', '218');
// const style = svg.attr('style');
// 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
// Class01 <|-- AveryLongClass : Cool
// Class01 : size()
// Class01 : int chimp
// Class01 : int gorilla
// Class01 : -int privateChimp
// Class01 : +int publicGorilla
// Class01 : #int protectedMarmoset
// `,
// { class: { useMaxWidth: false } }
// );
// cy.get('svg')
// .should((svg) => {
// const width = parseFloat(svg.attr('width'));
// // 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');
expect(style).to.match(/^max-width: [\d.]+px;$/);
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', () => {
@ -121,7 +121,7 @@ describe('Flowchart v2', () => {
const width = parseFloat(svg.attr('width'));
// 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(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');
});
});
@ -371,25 +371,25 @@ flowchart TD
E[(red text)] -->|default style| F((blue text))
G>red text] -->|default style| H{blue text}
I{{red text}} -->|default style| J[/blue text/]
K[\ red text\] -->|default style| L[/blue text\]
M[\ red text/] -->|default style| N[blue text]
K[\\ red text\\] -->|default style| L[/blue text\\]
M[\\ red text/] -->|default style| N[blue text];
linkStyle default color:Sienna;
style A stroke:#ff0000,fill:#ffcccc,color:#ff0000
style B stroke:#0000ff,fill:#ccccff,color:#0000ff
style C stroke:#ff0000,fill:#ffcccc,color:#ff0000
style D stroke:#0000ff,fill:#ccccff,color:#0000ff
style E stroke:#ff0000,fill:#ffcccc,color:#ff0000
style F stroke:#0000ff,fill:#ccccff,color:#0000ff
style G stroke:#ff0000,fill:#ffcccc,color:#ff0000
style H stroke:#0000ff,fill:#ccccff,color:#0000ff
style I stroke:#ff0000,fill:#ffcccc,color:#ff0000
style J stroke:#0000ff,fill:#ccccff,color:#0000ff
style K stroke:#ff0000,fill:#ffcccc,color:#ff0000
style L stroke:#0000ff,fill:#ccccff,color:#0000ff
style M stroke:#ff0000,fill:#ffcccc,color:#ff0000
style N stroke:#0000ff,fill:#ccccff,color:#0000ff
style A stroke:#ff0000,fill:#ffcccc,color:#ff0000;
style B stroke:#0000ff,fill:#ccccff,color:#0000ff;
style C stroke:#ff0000,fill:#ffcccc,color:#ff0000;
style D stroke:#0000ff,fill:#ccccff,color:#0000ff;
style E stroke:#ff0000,fill:#ffcccc,color:#ff0000;
style F stroke:#0000ff,fill:#ccccff,color:#0000ff;
style G stroke:#ff0000,fill:#ffcccc,color:#ff0000;
style H stroke:#0000ff,fill:#ccccff,color:#0000ff;
style I stroke:#ff0000,fill:#ffcccc,color:#ff0000;
style J stroke:#0000ff,fill:#ccccff,color:#0000ff;
style K stroke:#ff0000,fill:#ffcccc,color:#ff0000;
style L stroke:#0000ff,fill:#ccccff,color:#0000ff;
style M stroke:#ff0000,fill:#ffcccc,color:#ff0000;
style N stroke:#0000ff,fill:#ccccff,color:#0000ff;
`,
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose', logLevel:2}
);
});
it('61: fontawesome icons in edge labels', () => {
@ -462,4 +462,175 @@ flowchart TD
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
);
});
it('66: More nested subgraph cases (TB)', () => {
imgSnapshotTest(
`
flowchart TB
subgraph two
b1
end
subgraph three
c2
end
three --> two
two --> c2
`,
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
);
});
it('67: More nested subgraph cases (RL)', () => {
imgSnapshotTest(
`
flowchart RL
subgraph two
b1
end
subgraph three
c2
end
three --> two
two --> c2
`,
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
);
});
it('68: More nested subgraph cases (BT)', () => {
imgSnapshotTest(
`
flowchart BT
subgraph two
b1
end
subgraph three
c2
end
three --> two
two --> c2
`,
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
);
});
it('69: More nested subgraph cases (LR)', () => {
imgSnapshotTest(
`
flowchart LR
subgraph two
b1
end
subgraph three
c2
end
three --> two
two --> c2
`,
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
);
});
it('70: Handle nested subgraph cases (TB) link out and link between subgraphs', () => {
imgSnapshotTest(
`
flowchart TB
subgraph S1
sub1 -->sub2
end
subgraph S2
sub4
end
S1 --> S2
sub1 --> sub4
`,
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
);
});
it('71: Handle nested subgraph cases (RL) link out and link between subgraphs', () => {
imgSnapshotTest(
`
flowchart RL
subgraph S1
sub1 -->sub2
end
subgraph S2
sub4
end
S1 --> S2
sub1 --> sub4
`,
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
);
});
it('72: Handle nested subgraph cases (BT) link out and link between subgraphs', () => {
imgSnapshotTest(
`
flowchart BT
subgraph S1
sub1 -->sub2
end
subgraph S2
sub4
end
S1 --> S2
sub1 --> sub4
`,
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
);
});
it('74: Handle nested subgraph cases (RL) link out and link between subgraphs', () => {
imgSnapshotTest(
`
flowchart RL
subgraph S1
sub1 -->sub2
end
subgraph S2
sub4
end
S1 --> S2
sub1 --> sub4
`,
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
);
});
it('74: Handle labels for multiple edges from and to the same couple of nodes', () => {
imgSnapshotTest(
`
flowchart RL
subgraph one
a1 -- l1 --> a2
a1 -- l2 --> a2
end
`,
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
);
});
it('2050: handling of different rendering direction in subgraphs', () => {
imgSnapshotTest(
`
flowchart LR
subgraph TOP
direction TB
subgraph B1
direction RL
i1 -->f1
end
subgraph B2
direction BT
i2 -->f2
end
end
A --> TOP --> B
B1 --> B2
`,
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
);
});
});

View File

@ -258,4 +258,40 @@ describe('Gantt diagram', () => {
expect(svg).to.not.have.attr('style');
});
});
it('should render a gantt diagram with data labels at the top when topAxis is true', () => {
imgSnapshotTest(
`
gantt
dateFormat YYYY-MM-DD
axisFormat %d/%m
title Adding GANTT diagram to mermaid
excludes weekdays 2014-01-10
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
`,
{ gantt: { topAxis: true } }
);
});
});

View File

@ -32,8 +32,11 @@ section Order from website
it('should render a user journey diagram when useMaxWidth is true (default)', () => {
renderGraph(
`journey
title Adding journey diagram functionality to mermaid
title E-Commerce
section Order from website
Add to cart: 5: Me
section Checkout from website
Add payment details: 5: Me
`,
{ journey: { useMaxWidth: true } }
);
@ -42,29 +45,24 @@ section Order from website
expect(svg).to.have.attr('width', '100%');
expect(svg).to.have.attr('height');
const height = parseFloat(svg.attr('height'));
expect(height).to.eq(20);
expect(height).to.eq(565);
const style = svg.attr('style');
expect(style).to.match(/^max-width: [\d.]+px;$/);
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
expect(maxWidthValue).to.eq(400);
expect(maxWidthValue).to.eq(700);
});
});
it('should render a user journey diagram when useMaxWidth is false', () => {
renderGraph(
imgSnapshotTest(
`journey
title Adding journey diagram functionality to mermaid
title E-Commerce
section Order from website
Add to cart: 5: Me
section Checkout from website
Add payment details: 5: Me
`,
{ journey: { useMaxWidth: false } }
);
cy.get('svg')
.should((svg) => {
const height = parseFloat(svg.attr('height'));
const width = parseFloat(svg.attr('width'));
expect(height).to.eq(20);
expect(width).to.eq(400);
expect(svg).to.not.have.attr('style');
});
});
});

View File

@ -624,7 +624,7 @@ context('Sequence diagram', () => {
expect(svg).to.have.attr('width', '100%');
expect(svg).to.have.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');
expect(style).to.match(/^max-width: [\d.]+px;$/);
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
@ -664,7 +664,7 @@ context('Sequence diagram', () => {
.should((svg) => {
const height = parseFloat(svg.attr('height'));
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%
expect(width).to.be.within(820 * .95, 820 * 1.05);
expect(svg).to.not.have.attr('style');

View File

@ -329,6 +329,37 @@ describe('State diagram', () => {
}
);
});
it('v2 it should be possibel to use a choice', () => {
imgSnapshotTest(
`
stateDiagram-v2
[*] --> Off
Off --> On
state MyChoice [[choice]]
On --> MyChoice
MyChoice --> Washing
MyChoice --> Drying
Washing --> Finished
Finished --> [*]
`,
{
logLevel: 0,
}
);
});
it('v2 width of compond state should grow with title if title is wider', () => {
imgSnapshotTest(
`
stateDiagram-v2
state "Long state name" as NotShooting {
a-->b
}
`,
{
logLevel: 0,
}
);
});
it('v2 Simplest composite state', () => {
imgSnapshotTest(
`
@ -354,6 +385,58 @@ describe('State diagram', () => {
}
);
});
it('v2 should handle multiple notes added to one state', () => {
imgSnapshotTest(
`
stateDiagram-v2
MyState
note left of MyState : I am a leftie
note right of MyState : I am a rightie
`,
{
logLevel: 0, fontFamily: 'courier',
}
);
});
it('v2 should handle different rendering directions in composite states', () => {
imgSnapshotTest(
`
stateDiagram-v2
direction LR
state A {
direction BT
a --> b
}
state C {
direction RL
c --> d
}
A --> C
`,
{
logLevel: 0, fontFamily: 'courier',
}
);
});
it('v2 handle transition from one state in a composite state to a composite state', () => {
imgSnapshotTest(
`
stateDiagram-v2
state S1 {
sub1 -->sub2
}
state S2 {
sub4
}
S1 --> S2
sub1 --> sub4
`,
{
logLevel: 0, fontFamily: 'courier',
}
);
});
it('v2 should render a state diagram when useMaxWidth is true (default)', () => {
renderGraph(
`
@ -369,7 +452,7 @@ describe('State diagram', () => {
expect(svg).to.have.attr('width', '100%');
expect(svg).to.have.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');
expect(style).to.match(/^max-width: [\d.]+px;$/);
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
@ -391,7 +474,7 @@ describe('State diagram', () => {
.should((svg) => {
const height = parseFloat(svg.attr('height'));
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%
expect(width).to.be.within(135 * .95, 135 * 1.05);
expect(svg).to.not.have.attr('style');

View File

@ -358,12 +358,14 @@ describe('State diagram', () => {
expect(svg).to.have.attr('width', '100%');
expect(svg).to.have.attr('height');
const height = parseFloat(svg.attr('height'));
expect(height).to.eq(139);
expect(height).to.be.within(176,178);
const style = svg.attr('style');
expect(style).to.match(/^max-width: [\d.]+px;$/);
const maxWidthValue = parseFloat(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(112 * .95, 112 * 1.05);
// Todo investigate difference
// expect(maxWidthValue).to.be.within(112 * .95, 112 * 1.05);
expect(maxWidthValue).to.be.within(130, 140);
});
});
it('should render a state diagram when useMaxWidth is false', () => {
@ -379,9 +381,12 @@ describe('State diagram', () => {
.should((svg) => {
const height = parseFloat(svg.attr('height'));
const width = parseFloat(svg.attr('width'));
expect(height).to.eq(139);
expect(height).to.be.within(176,178);
// use within because the absolute value can be slightly different depending on the environment ±5%
expect(width).to.be.within(112 * .95, 112 * 1.05);
// Todo investigate difference
// expect(width).to.be.within(112 * .95, 112 * 1.05);
expect(width).to.be.within(130, 140);
expect(svg).to.not.have.attr('style');
});
});

View File

@ -30,6 +30,7 @@ if (location.href.match('test-html-escaping')) {
code = code3;
}
mermaid.initialize({
theme: 'default',
// fontFamily: '"Lucida Console", Monaco, monospace',

View File

@ -0,0 +1,6 @@
const div = parent.document.createElement('div');
div.id = 'the-malware';
div.className = 'malware';
div.innerHTML = 'XSS Succeeded';
parent.document.getElementsByTagName('body')[0].appendChild(div);
throw new Error('XSS Succeded');

View File

@ -10,134 +10,129 @@
<style>
body {
/* background: rgb(221, 208, 208); */
/* background:#333; */
background:#333;
font-family: 'Arial';
/* font-size: 18px !important; */
}
h1 { color: grey;}
.mermaid2 {
.mermaid2,.mermaid3 {
display: none;
}
.mermaid svg {
font-size: 12px !important;
/* font-size: 18px !important; */
}
</style>
</head>
<body>
<h1>info below</h1>
<div>info below</div>
<div class="flex">
<div class="mermaid2" style="width: 100%; height: 400px;">
%%{init: { "logLevel": 1, "er": {"fontSize":18 }} }%%
erDiagram
CUSTOMER }|..|{ DELIVERY-ADDRESS : has
CUSTOMER ||--o{ ORDER : places
CUSTOMER ||--o{ INVOICE : "liable for"
DELIVERY-ADDRESS ||--o{ ORDER : receives
INVOICE ||--|{ ORDER : covers
ORDER ||--|{ ORDER-ITEM : includes
PRODUCT-CATEGORY ||--|{ PRODUCT : contains
PRODUCT ||--o{ ORDER-ITEM : "ordered in"
</div>
<div class="mermaid2" style="width: 50%; height: 400px;">
flowchart TD
A[Christmas] ==> D
A[Christmas] -->|Get money| B(Go shopping)
A[Christmas] ==> C
subgraph T ["Test"]
A
B
C
end
classDef Test fill:#F84E68,stroke:#333,color:white;
class A,T Test
classDef TestSub fill:green;
class T TestSub
linkStyle 0,1 color:orange, stroke: orange;
</div>
<div class="mermaid" style="width: 50%; height: 20%;">
%%{init:{"theme":"base", "themeVariables": {"primaryColor":"#411d4e", "titleColor":"white", "darkMode":true}}}%%
flowchart LR
subgraph A
a --> b
end
subgraph B
i -->f
end
A --> B </div>
<div class="mermaid2" style="width: 50%; height: 20%;">
flowchart TD
C -->|fa:fa-car Car| F[fa:fa-car Car]
</div>
<div class="mermaid" style="width: 50%; height: 20%;">
flowchart LR
classDef dark fill:#000,stroke:#000,stroke-width:4px,color:#fff
Lorem --> Ipsum --> Dolor
class Lorem,Dolor dark
</div>
<div class="mermaid2" style="width: 50%; height: 20%;">
%%{init: {'theme': 'base' }}%%
%%{init2: { 'logLevel': 0, 'theme': 'forest'} }%%
flowchart TD
L1 --- L2
L2 --- C
M1 ---> C
R1 .-> R2
R2 <.-> C
C -->|Label 1| E1
C <-- Label 2 ---> E2
C ----> E3
C <-...-> E4
C ======> E5
</div>
<div class="mermaid2" style="width: 50%; height: 21%;">
flowchart LR
A[red text] -->|default style| B(blue text)
C([red text]) -->|default style| D[[blue text]]
E[(red text)] -->|default style| F((blue text))
G>red text] -->|default style| H{blue text}
I{{red text}} -->|default style| J[/blue text/]
K[
ed text] -->|default style| L[/blue text]
M[
ed text/] -->|default style| N[blue text]
linkStyle default color:Sienna;
style A stroke:#ff0000,fill:#ffcccc,color:#ff0000
style B stroke:#0000ff,fill:#ccccff,color:#0000ff
style C stroke:#ff0000,fill:#ffcccc,color:#ff0000
style D stroke:#0000ff,fill:#ccccff,color:#0000ff
style E stroke:#ff0000,fill:#ffcccc,color:#ff0000
style F stroke:#0000ff,fill:#ccccff,color:#0000ff
style G stroke:#ff0000,fill:#ffcccc,color:#ff0000
style H stroke:#0000ff,fill:#ccccff,color:#0000ff
style I stroke:#ff0000,fill:#ffcccc,color:#ff0000
style J stroke:#0000ff,fill:#ccccff,color:#0000ff
style K stroke:#ff0000,fill:#ffcccc,color:#ff0000
style L stroke:#0000ff,fill:#ccccff,color:#0000ff
style M stroke:#ff0000,fill:#ffcccc,color:#ff0000
style N stroke:#0000ff,fill:#ccccff,color:#0000ff
</div>
<div class="mermaid2" style="width: 100%; height: 20%;">
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
</div>
<div class="mermaid3" style="width: 100%; height: 20%;">
stateDiagram
state CompositeState {
YourState123456789012345123456789123456789012345123456789123456789012345123456789123456789012345123456789 --> MyState:a label
}
</div>
<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"}}%%
sequenceDiagram
Alice->>Bob: Hi Bob
Bob->>Alice: Hi Alice
</div>
<div class="mermaid2">
%%{init: { 'theme':'base', '__proto__': {'polluted': 'asdf'}} }%%
%%{init: { 'theme':'base', '__proto__': {'polluted': 'asdf'}} }%%
graph LR
A --> B
</div>
<div class="mermaid2" style="width: 100%; height: 20%;">
flowchart TD
Link --> b
click Link href "&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29" "Tooltip for
Amet"
</div>
<div class="mermaid2" style="width: 100%; height: 20%;">
stateDiagram-v2
state CS {
state ACS {
YourState
}
}
</div>
<div class="mermaid2" style="width: 100%; height: 20%;">
stateDiagram-v2
[*] --> Active
state Active {
[*] --> NumLockOff
NumLockOff --> NumLockOn : EvNumLockPressed
NumLockOn --> NumLockOff : EvNumLockPressed
--
[*] --> CapsLockOff
CapsLockOff --> CapsLockOn : EvCapsLockPressed
CapsLockOn --> CapsLockOff : EvCapsLockPressed
}
state SomethingElse {
A --> B
B --> A
}
Active --> SomethingElse
note right of SomethingElse : This is the note to the right.
SomethingElse --> [*] </div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
theme: 'dark',
// theme: 'forest',
// themeVariables:{primaryColor: '#ff0000'},
// arrowMarkerAbsolute: true,
arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 0,
flowchart: { nodeSpacing: 10, curve: 'cardinal', htmlLabels: true },
htmlLabels: true,
logLevel: 2,
flowchart: { nodeSpacing: 10, curve: 'cardinal', htmlLabels: false },
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorFontFamily: 'courier',actorMargin: 50, showSequenceNumbers: false },
// sequenceDiagram: { actorMargin: 300 } // deprecated
fontFamily: '"arial", sans-serif',
fontFamily: 'courier',
// fontFamily: '"times", sans-serif',
// fontFamily: 'courier',
state:{
nodeSpacing: 50,
rankSpacing: 50,
defaultRenderer: 'dagre-wrapper',
},
logLevel:0,
fontSize: 18,
curve: 'cardinal',
securityLevel: 'loose',
securityLevel: 'strict',
// themeVariables: {relationLabelColor: 'red'}
});
function callback(){alert('It worked');}
</script>

View File

@ -0,0 +1,93 @@
<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';
/* font-size: 18px !important; */
}
h1 { color: grey;}
.mermaid2 {
display: none;
}
.mermaid svg {
/* font-size: 18px !important; */
}
.malware {
position: fixed;
bottom:0;
left:0;
right:0;
height: 150px;
background: red;
color: black;
display: flex;
display: flex;
justify-content: center;
align-items: center;
font-family: monospace;
font-size: 72px;
}
</style>
</head>
<body>
<div>Security check</div>
<div class="flex">
<div id="diagram" class="mermaid"></div>
<div id="res" class=""></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,
state: {
defaultRenderer: 'dagre-wrapper',
},
flowchart: {
// defaultRenderer: 'dagre-wrapper',
nodeSpacing: 10, curve: 'cardinal', htmlLabels: true
},
htmlLabels: false,
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorFontFamily: 'courier',actorMargin: 50, showSequenceNumbers: false },
// sequenceDiagram: { actorMargin: 300 } // deprecated
// fontFamily: '"times", sans-serif',
// fontFamily: 'courier',
fontSize: 18,
curve: 'basis',
securityLevel: 'strict',
startOnLoad: false
// themeVariables: {relationLabelColor: 'red'}
});
function callback(){alert('It worked');}
var diagram = "%%{init: {\"flowchart\": {\"htmlLabels\": \"false\"}} }%%\n";
diagram += "flowchart\n";
diagram += "A[\"<ifra";
diagram += "me srcdoc='<scrip";
diagram += "t src=http://localhost:9000/exploit.js>";
diagram += "</scr"
diagram += "ipt>'></iframe>\"]";
console.log(diagram);
// document.querySelector('#diagram').innerHTML = diagram;
mermaid.render('diagram', diagram, (res) => {
document.querySelector('#res').innerHTML = res;
});
</script>
</body>
</html>

210
cypress/platform/knsv3.html Normal file
View File

@ -0,0 +1,210 @@
<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';
/* font-size: 18px !important; */
}
h1 { color: grey;}
.mermaid2 {
display: none;
}
.mermaid svg {
/* font-size: 18px !important; */
}
</style>
</head>
<body>
<div>info below</div>
<div class="flex">
<div class="mermaid2" style="width: 100%; height: 400px;">
%%{init: { "logLevel": 1, "er": {"fontSize":18 }} }%%
erDiagram
CUSTOMER }|..|{ DELIVERY-ADDRESS : has
CUSTOMER ||--o{ ORDER : places
CUSTOMER ||--o{ INVOICE : "liable for"
DELIVERY-ADDRESS ||--o{ ORDER : receives
INVOICE ||--|{ ORDER : covers
ORDER ||--|{ ORDER-ITEM : includes
PRODUCT-CATEGORY ||--|{ PRODUCT : contains
PRODUCT ||--o{ ORDER-ITEM : "ordered in"
</div>
<div class="mermaid2" style="width: 50%; height: 400px;">
flowchart TD
A[Christmas] ==> D
A[Christmas] -->|Get money| B(Go shopping)
A[Christmas] ==> C
subgraph T ["Test"]
A
B
C
end
classDef Test fill:#F84E68,stroke:#333,color:white;
class A,T Test
classDef TestSub fill:green;
class T TestSub
linkStyle 0,1 color:orange, stroke: orange;
</div>
<div class="mermaid" style="width: 100%; height: 20%;">
flowchart TB
subgraph S1
sub1 -->sub2
end
subgraph S2
sub4
end
S1 --> S2
sub1 --> sub4
</div>
<div class="mermaid2" style="width: 100%; height: 20%;">
flowchart TB
c1-->a2
subgraph one
a1-->a2
end
subgraph two
b1-->b2
end
subgraph three
c1-->c2
end
one --> two
three --> two
two --> c2
</div>
<div class="mermaid2" style="width: 100%; height: 20%;">
stateDiagram-v2
state S1 {
sub1 -->sub2
}
state S2 {
sub4
}
S1 --> S2
sub1 --> sub4
</div>
<div class="mermaid2" style="width: 100%; height: 20%;">
requirementDiagram
requirement test_req {
id: 1
text: the test text.
risk: high
verifymethod: test
}
functionalRequirement test_req2 {
id: 1.1
text: the second test text.
risk: low
verifymethod: inspection
}
performanceRequirement test_req3 {
id: 1.2
text: the third test text.
risk: medium
verifymethod: demonstration
}
element test_entity {
type: simulation
}
element test_entity2 {
type: word doc
docRef: reqs/test_entity
}
test_entity - satisfies -> test_req2
test_req - traces -> test_req2
test_req - contains -> test_req3
test_req <- copies - test_entity2
</div>
<div class="mermaid2" style="width: 50%; height: 20%;">
flowchart LR
classDef dark fill:#000,stroke:#000,stroke-width:4px,color:#fff
Lorem --> Ipsum --> Dolor
class Lorem,Dolor dark
</div>
<div class="mermaid2" style="width: 50%; height: 20%;">
%%{init: {'theme': 'base' }}%%
%%{init2: { 'logLevel': 0, 'theme': 'forest'} }%%
flowchart TD
L1 --- L2
L2 --- C
M1 ---> C
R1 .-> R2
R2 <.-> C
C -->|Label 1| E1
C <-- Label 2 ---> E2
C ----> E3
C <-...-> E4
C ======> E5
</div>
<div class="mermaid2" style="width: 50%; height: 21%;">
flowchart LR
A[red text] -->|default style| B(blue text)
C([red text]) -->|default style| D[[blue text]]
E[(red text)] -->|default style| F((blue text))
G>red text] -->|default style| H{blue text}
I{{red text}} -->|default style| J[/blue text/]
K[
ed text] -->|default style| L[/blue text]
M[
ed text/] -->|default style| N[blue text]
linkStyle default color:Sienna;
style A stroke:#ff0000,fill:#ffcccc,color:#ff0000
style B stroke:#0000ff,fill:#ccccff,color:#0000ff
style C stroke:#ff0000,fill:#ffcccc,color:#ff0000
style D stroke:#0000ff,fill:#ccccff,color:#0000ff
style E stroke:#ff0000,fill:#ffcccc,color:#ff0000
style F stroke:#0000ff,fill:#ccccff,color:#0000ff
style G stroke:#ff0000,fill:#ffcccc,color:#ff0000
style H stroke:#0000ff,fill:#ccccff,color:#0000ff
style I stroke:#ff0000,fill:#ffcccc,color:#ff0000
style J stroke:#0000ff,fill:#ccccff,color:#0000ff
style K stroke:#ff0000,fill:#ffcccc,color:#ff0000
style L stroke:#0000ff,fill:#ccccff,color:#0000ff
style M stroke:#ff0000,fill:#ffcccc,color:#ff0000
style N stroke:#0000ff,fill:#ccccff,color:#0000ff
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
theme: 'neutral',
arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 0,
flowchart: { nodeSpacing: 10, curve: 'cardinal', htmlLabels: true },
htmlLabels: true,
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorFontFamily: 'courier',actorMargin: 50, showSequenceNumbers: false },
// sequenceDiagram: { actorMargin: 300 } // deprecated
// fontFamily: '"times", sans-serif',
// fontFamily: 'courier',
fontSize: 18,
curve: 'cardinal',
securityLevel: 'loose',
// themeVariables: {relationLabelColor: 'red'}
});
function callback(){alert('It worked');}
</script>
</body>
</html>

View File

@ -38,6 +38,19 @@
graph LR
A --> B
</div>
<div class="mermaid">
%%{init: { 'theme':'base', '__proto__': {'polluted': 'asdf'}} }%%
%%{init: { 'theme':'base', '__proto__': {'polluted': 'asdf'}} }%%
graph LR
A --> B
</div>
<div class="mermaid">
%%{init: { 'prototype': {'__proto__': {'polluted': 'test'}}} }%%
%%{init: { 'prototype': {'__proto__': {'polluted': 'test'}}} }%%
sequenceDiagram
Alice->>Bob: Hi Bob
Bob->>Alice: Hi Alice
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.initialize({

View File

@ -0,0 +1,94 @@
<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';
/* font-size: 18px !important; */
}
h1 { color: grey;}
.mermaid2 {
display: none;
}
.mermaid svg {
/* font-size: 18px !important; */
}
.malware {
position: fixed;
bottom:0;
left:0;
right:0;
height: 150px;
background: red;
color: black;
display: flex;
display: flex;
justify-content: center;
align-items: center;
font-family: monospace;
font-size: 72px;
}
</style>
</head>
<body>
<div>Security check</div>
<div class="flex">
<div id="diagram" class="mermaid"></div>
<div id="res" class=""></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,
state: {
defaultRenderer: 'dagre-wrapper',
},
flowchart: {
// defaultRenderer: 'dagre-wrapper',
nodeSpacing: 10, curve: 'cardinal', htmlLabels: true
},
htmlLabels: false,
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorFontFamily: 'courier',actorMargin: 50, showSequenceNumbers: false },
// sequenceDiagram: { actorMargin: 300 } // deprecated
// fontFamily: '"times", sans-serif',
// fontFamily: 'courier',
fontSize: 18,
curve: 'basis',
securityLevel: 'strict',
startOnLoad: false,
secure: ['secure', 'securityLevel', 'startOnLoad', 'maxTextSize']
// themeVariables: {relationLabelColor: 'red'}
});
function callback(){alert('It worked');}
var diagram = "%%{init: {\"flowchart\": {\"htmlLabels\": \"true\"}} }%%\n";
diagram += "flowchart\n";
diagram += "A[\"<ifra";
diagram += "me srcdoc='<scrip";
diagram += "t src=http://localhost:9000/exploit.js>";
diagram += "</scr"
diagram += "ipt>'></iframe>\"]";
console.log(diagram);
// document.querySelector('#diagram').innerHTML = diagram;
mermaid.render('diagram', diagram, (res) => {
document.querySelector('#res').innerHTML = res;
});
</script>
</body>
</html>

View File

@ -0,0 +1,99 @@
<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';
/* font-size: 18px !important; */
}
h1 { color: grey;}
.mermaid2 {
display: none;
}
.mermaid svg {
/* font-size: 18px !important; */
}
.malware {
position: fixed;
bottom:0;
left:0;
right:0;
height: 150px;
background: red;
color: black;
display: flex;
display: flex;
justify-content: center;
align-items: center;
font-family: monospace;
font-size: 72px;
}
</style>
</head>
<body>
<div>Security check</div>
<div class="flex">
<div id="diagram" class="mermaid"></div>
<div id="res" class=""></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,
state: {
defaultRenderer: 'dagre-wrapper',
},
flowchart: {
// defaultRenderer: 'dagre-wrapper',
nodeSpacing: 10, curve: 'cardinal', htmlLabels: true
},
htmlLabels: true,
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorFontFamily: 'courier',actorMargin: 50, showSequenceNumbers: false },
// sequenceDiagram: { actorMargin: 300 } // deprecated
// fontFamily: '"times", sans-serif',
// fontFamily: 'courier',
fontSize: 18,
curve: 'basis',
securityLevel: 'antiscript',
startOnLoad: false,
secure: ['secure', 'securityLevel', 'startOnLoad', 'maxTextSize']
// themeVariables: {relationLabelColor: 'red'}
});
function callback(){alert('It worked');}
function xssAttack(){
const div = document.createElement('div')
div.id = 'the-malware'
div.className = 'malware'
div.innerHTML = 'XSS Succeeded'
document.getElementsByTagName('body')[0].appendChild(div);
throw new Error('XSS Succeded');
}
var diagram = "graph LR\n";
diagram += "B-->D\(\"<img onerror=location=\`java";
// diagram += "script\u003aalert\u0028document.domain\u0029\` src=x>\"\);\n";
diagram += "script\x3a;xssAttack\u0028\u0029\` src=x>\"\);\n";
console.log(diagram);
// document.querySelector('#diagram').innerHTML = diagram;
mermaid.render('diagram', diagram, (res) => {
console.log(res);
document.querySelector('#res').innerHTML = res;
});
</script>
</body>
</html>

View File

@ -0,0 +1,97 @@
<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';
/* font-size: 18px !important; */
}
h1 { color: grey;}
.mermaid2 {
display: none;
}
.mermaid svg {
/* font-size: 18px !important; */
}
.malware {
position: fixed;
bottom:0;
left:0;
right:0;
height: 150px;
background: red;
color: black;
display: flex;
display: flex;
justify-content: center;
align-items: center;
font-family: monospace;
font-size: 72px;
}
</style>
</head>
<body>
<div>Security check</div>
<div class="flex">
<div id="diagram" class="mermaid"></div>
<div id="res" class=""></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,
state: {
defaultRenderer: 'dagre-wrapper',
},
flowchart: {
// defaultRenderer: 'dagre-wrapper',
nodeSpacing: 10, curve: 'cardinal', htmlLabels: true
},
htmlLabels: true,
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorFontFamily: 'courier',actorMargin: 50, showSequenceNumbers: false },
// sequenceDiagram: { actorMargin: 300 } // deprecated
// fontFamily: '"times", sans-serif',
// fontFamily: 'courier',
fontSize: 18,
curve: 'basis',
securityLevel: 'antiscript',
startOnLoad: false,
secure: ['secure', 'securityLevel', 'startOnLoad', 'maxTextSize']
// themeVariables: {relationLabelColor: 'red'}
});
function callback(){alert('It worked');}
function xssAttack(){
const div = document.createElement('div')
div.id = 'the-malware'
div.className = 'malware'
div.innerHTML = 'XSS Succeeded'
document.getElementsByTagName('body')[0].appendChild(div);
throw new Error('XSS Succeded');
}
var diagram = "graph LR\n";
diagram += "A(<img/src/onerror=xssAttack`1`>)";
// diagram += "script\u003aalert\u0028document.domain\u0029\` src=x>\"\);\n";
console.log(diagram);
// document.querySelector('#diagram').innerHTML = diagram;
mermaid.render('diagram', diagram, (res) => {
console.log(res);
document.querySelector('#res').innerHTML = res;
});
</script>
</body>
</html>

View File

@ -16,10 +16,8 @@
// // `config` is the resolved Cypress config
// }
let percyHealthCheck = require("@percy/cypress/task");
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
on("task", percyHealthCheck);
};

View File

@ -14,7 +14,8 @@
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
import './commands';
import '@percy/cypress';
// Alternatively you can use CommonJS syntax:
// require('./commands')

3790
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

71788
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

12
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

@ -1,19 +1,27 @@
# Configuration
Configuration is the second half of Mermaid for one or for many diagrams.
Configuration is the second half of Mermaid, after deployment. Together Deployment and Configuration constitute the whole of Mermaid.
This section will briefly introduce the different methods of configuring of the behaviors and apperances of Mermaid Diagrams.
The Following are the most commonly used methods, and are all tied to the [Deployment](./n00b-gettingStarted.md) methods.
This section will introduce the different methods of configuring of the behaviors and apperances of Mermaid Diagrams.
The Following are the most commonly used methods, and are all tied to Mermaid [Deployment](./n00b-gettingStarted.md) methods.
## Configuration Section in the [Live Editor](./Live-Editor.md).
## The `initialize()` call, for when Mermaid is called via an API, or through a <script> tag.
## [Directives](./directives.md),
allows the limited reconfiguration of a diagram just before it is rendered. It can alter the font style, color and other aesthetic aspects of the diagram. you can pass a directive alongside your defintion inside `%%{ }%%`, either above or below your diagram defintion.
## Theme Creation:
An application of using Directives to change [Themes](./theming.md). `Theme` is an value within mermaid's configuration that dictates the color scheme for diagrams.
If you are interested in altering and customizing your Mermaid Diagrams, you will find the methods and values available for [Configuration](./Setup.md) here. It includes themes
1. Configuration Section in the [Live Editor](./Live-Editor.md).
2. The [Initialize call](), for when Mermaid is called via an API, or through a <script> tag.
3. [Directives](./directives.md), these are perhaps the most accessible of all, as they can be used by the
a. [Themes](./theming.md) are set up using `%%{init}%%` Directives and happen to be the fastest way of changing
If you are interested in altering and customizing your Mermaid Diagrams, this list of [Configurations](./Setup.md) would be helpful.

View File

@ -2,23 +2,27 @@
**Mermaid lets you create diagrams and visualizations using text and code.**
It is a Javascript based diagramming and charting tool that renders Markdown-inspired text definitions to create and modify diagrams dynamically.
It is a Javascript based diagramming and charting tool that renders Markdown-inspired text definitions to create and modify diagrams dynamically.
>If you are familiar with Markdown you should have no problem learning [Mermaid's Syntax](./n00b-syntaxReference.md).
![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)
<!-- **Edit this Page** [![N|Solid](img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/README.md) -->
[![Build Status](https://travis-ci.org/mermaid-js/mermaid.svg?branch=master)](https://travis-ci.org/mermaid-js/mermaid) [![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.com/package/mermaid) [![Coverage Status](https://coveralls.io/repos/github/mermaid-js/mermaid/badge.svg?branch=master)](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) [![This project is using Percy.io for visual regression testing.](https://percy.io/static/images/percy-badge.svg)](https://percy.io/Mermaid/mermaid)
<!-- Mermaidn book banner -->
[![banner](img/book-banner-pre-release.jpg)](https://mermaid-js.github.io/mermaid/landing/)
<!-- <Main description> -->
The main purpose of Mermaid is to help with Visualizing Documentation, and helping it catch up with Development.
> Documentation-Rot is a Catch-22 that Mermaid helps to solve.
Diagramming and Documentation costs precious developer time and gets outdated quickly.
But not having diagrams or docs ruins productivity and hurts organizational learning.
But not having diagrams or docs ruins productivity and hurts organizational learning.
Mermaid addresses this Catch-22 by cutting the time, effort and tooling that is required to create modifiable diagrams and charts, for smarter and more reusable content.
Mermaid, as a text-based diagramming tool allows for quick and easy updates, it can also be made part of production scripts (and other pieces of code), to make documentation much easier.
@ -42,7 +46,7 @@ For a more detailed introduction to Mermaid and some of it's more basic uses, lo
# Diagram Types
### [Flowchart](/flowchart?id=flowcharts-basic-syntax)
### [Flowchart](./flowchart.md?id=flowcharts-basic-syntax)
```
graph TD;
@ -54,7 +58,7 @@ graph TD;
![Flowchart](img/flow.png)
### [Sequence diagram](/sequenceDiagram)
### [Sequence diagram](./sequenceDiagram.md)
```
sequenceDiagram
@ -72,7 +76,7 @@ sequenceDiagram
![Sequence diagram](img/sequence.png)
### [Gantt diagram](/gantt)
### [Gantt diagram](./gantt.md)
```
gantt
@ -89,7 +93,7 @@ Future task2 : des4, after des3, 5d
![Gantt diagram](img/gantt.png)
### [Class diagram](/classDiagram)
### [Class diagram](./classDiagram.md)
```
classDiagram
@ -133,7 +137,7 @@ merge newbranch
```
![Git graph](img/git.png)
### [Entity Relationship Diagram - :exclamation: experimental](/entityRelationshipDiagram)
### [Entity Relationship Diagram - :exclamation: experimental](./entityRelationshipDiagram.md)
```
erDiagram
@ -145,7 +149,7 @@ erDiagram
![ER diagram](img/simple-er.png)
### [User Journey Diagram](/user-journey)
### [User Journey Diagram](./user-journey.md)
```markdown
journey
@ -181,7 +185,7 @@ Latest Version: [https://unpkg.com/browse/mermaid@8.8.0/](https://unpkg.com/brow
## Deploying Mermaid
To Deploy Mermaid:
1. You will need to install node v10 or 12, which would have npm
1. You will need to install node v16, which would have npm
2. Download yarn using npm
3. Enter the following command: `yarn add mermaid`
4. You can then add mermaid as a dev dependency using this command:

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
This is list of publicly available Tutorials for using Mermaid.JS . This is intended as a basic introduction for the use of the Live Editor for generating diagrams, and deploying Mermaid.JS through HTML.
**Note that these tutorials might display an older interface, but the usage of the live-editor will largely be the same.
**Note that these tutorials might display an older interface, but the usage of the live-editor will largely be the same.**
For most purposes, you can use the [Live Editor](https://mermaid-js.github.io/mermaid-live-editor), to quickly and easily render a diagram.
@ -10,6 +10,8 @@ For most purposes, you can use the [Live Editor](https://mermaid-js.github.io/me
## Live-Editor Tutorials
The definitions that can be generated the Live-Editor are also backwards-compatible as of version 8.7.0.
[Chris Chinchilla: Hands on - Text-based diagrams with Mermaid](https://www.youtube.com/watch?v=4_LdV1cs2sA)
[GitLab Unfiltered: How to Create Mermaid Diagrams](https://www.youtube.com/watch?v=SQ9QmuTHuSI&t=438s)
[GitLab Unfiltered: Emilie adds a mermaid diagram to the handbook](https://www.youtube.com/watch?v=5RQqht3NNSE)

View File

@ -1,12 +1,10 @@
- Introduction 📊
- Introduction 📔
- [About mermaid](README.md)
- [Simple start to write diagrams](n00b-gettingStarted.md)
- [Overview for Beginners](n00b-overview.md)
- [About Mermaid](README.md)
- [Deployment](n00b-gettingStarted.md)
- [Syntax and Configuration](n00b-syntaxReference.md)
- Diagram Syntax 📊
- [Diagram syntax intro](n00b-syntaxReference.md)
- [Flowchart](flowchart.md)
- [Sequence diagram](sequenceDiagram.md)
- [Class Diagram](classDiagram.md)
@ -18,11 +16,11 @@
- [Requirement Diagram](requirementDiagram.md)
- [Other Examples](examples.md)
- Adding mermaid✒
- Deployment and Configuration ⚙
- [Tutorials](Tutorials.md)
- [API-Usage](usage.md)
- [Configuration handling in Mermaid API](Setup.md)
- [Mermaid API Configuration](Setup.md)
- [Directives](directives.md)
- [Theming](theming.md)
- [mermaid CLI](mermaidCLI.md)
@ -33,7 +31,7 @@
- [FAQ](faq.md)
- Contributions and Community 🙌
- [Overview for Beginners](n00b-overview.md)
- [Development and Contribution ](development.md)
- [Changelog](CHANGELOG.md)
- [Adding Diagrams ](newDiagram.md)

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
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

@ -74,7 +74,7 @@ To start working with the e2e tests:
The rendering tests are very straightforward to create. There is a function `imgSnapshotTest`, which takes a diagram in text form and the mermaid options, and it renders that diagram in Cypress.
When running in CI it will take a snapshot of the rendered diagram and compare it with the snapshot from last build and flag for review it if it differs.
When running in CI it will take a snapshot of the rendered diagram and compare it with the snapshot from last build and flag it for review if it differs.
This is what a rendering test looks like:

View File

@ -2,29 +2,64 @@
**Edit this Page** [![N|Solid](img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/flowchart.md)
All Flowcharts are composed of **nodes**, the geometric shapes and **edges**, the arrows or lines. The mermaid code defines the way that these **nodes** and **edges** are made and interact.
It can also accomodate different arrow types, multi directional arrows, and linking to and from subgraphs.
> **Important note**: 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).**
Node
### A node (default)
```
flowchart LR
id
```
```mermaid
flowchart LR
id
```
> **Note** The id is what is displayed in the box.
### A node with text
It is also possible to set text in the box that differs from the id. If this is done several times, it is the last text
found for the node that will be used. Also if you define edges for the node later on, you can omit text definitions. The
one previously defined will be used when rendering the box.
```
flowchart LR
id1[This is the text in the box]
```
```mermaid
flowchart LR
id1[This is the text in the box]
```
## Graph
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
```
```mermaid
graph TD
flowchart TD
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
```
```mermaid
graph LR
flowchart LR
Start --> Stop
```
@ -38,112 +73,71 @@ Possible FlowChart orientations are:
* RL - right to left
* LR - left to right
## 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.
> **Important note** 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
### A node (default)
```
graph LR
id
```
```mermaid
graph LR
id
```
> **Note** The id is what is displayed in the box.
### A node with text
It is also possible to set text in the box that differs from the id. If this is done several times, it is the last text
found for the node that will be used. Also if you define edges for the node later on, you can omit text definitions. The
one previously defined will be used when rendering the box.
```
graph LR
id1[This is the text in the box]
```
```mermaid
graph LR
id1[This is the text in the box]
```
## Node Shapes
## Node shapes
### A node with round edges
```
graph LR
flowchart LR
id1(This is the text in the box)
```
```mermaid
graph LR
flowchart LR
id1(This is the text in the box)
```
### A stadium-shaped node
```
graph LR
flowchart LR
id1([This is the text in the box])
```
```mermaid
graph LR
flowchart LR
id1([This is the text in the box])
```
### A node in a subroutine shape
```
graph LR
flowchart LR
id1[[This is the text in the box]]
```
```mermaid
graph LR
flowchart LR
id1[[This is the text in the box]]
```
### A node in a cylindrical shape
```
graph LR
flowchart LR
id1[(Database)]
```
```mermaid
graph LR
flowchart LR
id1[(Database)]
```
### A node in the form of a circle
```
graph LR
flowchart LR
id1((This is the text in the circle))
```
```mermaid
graph LR
flowchart LR
id1((This is the text in the circle))
```
### A node in an asymmetric shape
```
graph LR
flowchart LR
id1>This is the text in the box]
```
```mermaid
graph LR
flowchart LR
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.*
@ -151,65 +145,65 @@ Currently only the shape above is possible and not its mirror. *This might chang
### A node (rhombus)
```
graph LR
flowchart LR
id1{This is the text in the box}
```
```mermaid
graph LR
flowchart LR
id1{This is the text in the box}
```
### A hexagon node
```
graph LR
flowchart LR
id1{{This is the text in the box}}
```
```mermaid
graph LR
flowchart LR
id1{{This is the text in the box}}
```
### Parallelogram
```
graph TD
flowchart TD
id1[/This is the text in the box/]
```
```mermaid
graph TD
flowchart TD
id1[/This is the text in the box/]
```
### Parallelogram alt
```
graph TD
flowchart TD
id1[\This is the text in the box\]
```
```mermaid
graph TD
flowchart TD
id1[\This is the text in the box\]
```
### Trapezoid
```
graph TD
flowchart TD
A[/Christmas\]
```
```mermaid
graph TD
flowchart TD
A[/Christmas\]
```
### Trapezoid alt
```
graph TD
flowchart TD
B[\Go shopping/]
```
```mermaid
graph TD
flowchart TD
B[\Go shopping/]
```
@ -220,110 +214,110 @@ Nodes can be connected with links/edges. It is possible to have different types
### A link with arrow head
```
graph LR
flowchart LR
A-->B
```
```mermaid
graph LR
flowchart LR
A-->B
```
### An open link
```
graph LR
flowchart LR
A --- B
```
```mermaid
graph LR
flowchart LR
A --- B
```
### Text on links
```
graph LR
flowchart LR
A-- This is the text! ---B
```
```mermaid
graph LR
flowchart LR
A-- This is the text ---B
```
or
```
graph LR
flowchart LR
A---|This is the text|B
```
```mermaid
graph LR
flowchart LR
A---|This is the text|B
```
### A link with arrow head and text
```
graph LR
flowchart LR
A-->|text|B
```
```mermaid
graph LR
flowchart LR
A-->|text|B
```
or
```
graph LR
flowchart LR
A-- text -->B
```
```mermaid
graph LR
flowchart LR
A-- text -->B
```
### Dotted link
```
graph LR;
flowchart LR;
A-.->B;
```
```mermaid
graph LR;
flowchart LR;
A-.->B;
```
### Dotted link with text
```
graph LR
flowchart LR
A-. text .-> B
```
```mermaid
graph LR
flowchart LR
A-. text .-> B
```
### Thick link
```
graph LR
flowchart LR
A ==> B
```
```mermaid
graph LR
flowchart LR
A ==> B
```
### Thick link with text
```
graph LR
flowchart LR
A == text ==> B
```
```mermaid
graph LR
flowchart LR
A == text ==> B
```
@ -331,48 +325,48 @@ graph LR
It is possible declare many links in the same line as per below:
```
graph LR
flowchart LR
A -- text --> B -- text2 --> C
```
```mermaid
graph LR
flowchart LR
A -- text --> B -- text2 --> C
```
It is also possible to declare multiple nodes links in the same line as per below:
```
graph LR
flowchart LR
a --> b & c--> d
```
```mermaid
graph LR
flowchart LR
a --> b & c--> d
```
You can then describe dependencies in a very expressive way. Like the one-liner below:
```
graph TB
flowchart TB
A & B--> C & D
```
```mermaid
graph TB
flowchart TB
A & B--> C & D
```
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.
This goes for expressive syntaxes as well.
```
graph TB
flowchart TB
A --> C
A --> D
B --> C
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
@ -387,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
@ -417,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:
```
graph TD
flowchart TD
A[Start] --> B{Is it?};
B -->|Yes| C[OK];
C --> D[Rethink];
@ -426,7 +420,7 @@ graph TD
```
```mermaid
graph TD
flowchart TD
A[Start] --> B{Is it?};
B -->|Yes| C[OK];
C --> D[Rethink];
@ -442,7 +436,7 @@ be added on the right side of the link. The following example is equivalent to
the previous one:
```
graph TD
flowchart TD
A[Start] --> B{Is it?};
B -- Yes --> C[OK];
C --> D[Rethink];
@ -451,7 +445,7 @@ graph TD
```
```mermaid
graph TD
flowchart TD
A[Start] --> B{Is it?};
B -->|Yes| C[OK];
C --> D[Rethink];
@ -476,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:
```
graph LR
flowchart LR
id1["This is the (text) in the box"]
```
```mermaid
graph LR
flowchart LR
id1["This is the (text) in the box"]
```
@ -489,11 +483,11 @@ graph LR
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;"]
```
```mermaid
graph LR
flowchart LR
A["A double quote:#quot;"] -->B["A dec char:#9829;"]
```
@ -510,7 +504,7 @@ end
An example below:
```
graph TB
flowchart TB
c1-->a2
subgraph one
a1-->a2
@ -523,7 +517,7 @@ graph TB
end
```
```mermaid
graph TB
flowchart TB
c1-->a2
subgraph one
a1-->a2
@ -539,14 +533,14 @@ graph TB
You can also set an explicit id for the subgraph.
```
graph TB
flowchart TB
c1-->a2
subgraph ide1 [one]
a1-->a2
end
```
```mermaid
graph TB
flowchart TB
c1-->a2
subgraph id1 [one]
a1-->a2
@ -555,7 +549,7 @@ graph TB
## 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
@ -591,6 +585,45 @@ flowchart TB
two --> c2
```
## Direction in subgraphs
With the graphtype flowcharts you can use the direction statement to set the direction which the subgraph will render like in this example.
```
flowchart LR
subgraph TOP
direction TB
subgraph B1
direction RL
i1 -->f1
end
subgraph B2
direction BT
i2 -->f2
end
end
A --> TOP --> B
B1 --> B2
```
```mermaid
flowchart LR
subgraph TOP
direction TB
subgraph B1
direction RL
i1 -->f1
end
subgraph B2
direction BT
i2 -->f2
end
end
A --> TOP --> B
B1 --> B2
```
## 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'`.
@ -614,7 +647,7 @@ Examples of tooltip usage below:
```
```
graph LR;
flowchart LR;
A-->B;
B-->C;
C-->D;
@ -627,7 +660,7 @@ graph LR;
The tooltip text is surrounded in double quotes. The styles of the tooltip are set by the class .mermaidTooltip.
```mermaid
graph LR
flowchart LR
A-->B;
B-->C;
C-->D;
@ -642,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):
```
graph LR;
flowchart LR;
A-->B;
B-->C;
C-->D;
@ -654,7 +687,7 @@ graph LR;
```
```mermaid
graph LR;
flowchart LR;
A-->B;
B-->C;
C-->D;
@ -669,7 +702,7 @@ Beginners tip, a full example using interactive links in a html context:
```html
<body>
<div class="mermaid">
graph LR;
flowchart LR;
A-->B;
B-->C;
C-->D;
@ -703,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
```
graph LR
flowchart LR
%% this is a comment A -- text --> B{node}
A -- text --> B -- text2 --> C
```
@ -727,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.
```
graph LR
flowchart LR
id1(Start)-->id2(Stop)
style id1 fill:#f9f,stroke:#333,stroke-width:4px
style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
```
```mermaid
graph LR
flowchart LR
id1(Start)-->id2(Stop)
style id1 fill:#f9f,stroke:#333,stroke-width:4px
style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
@ -742,7 +775,7 @@ graph LR
#### Classes
More convenient then defining the style every time is to define a class of styles and attach this class to the nodes that
More convenient than defining the style every time is to define a class of styles and attach this class to the nodes that
should have a different look.
a class definition looks like the example below:
@ -767,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:
```
graph LR
flowchart LR
A:::someclass --> B
classDef someclass fill:#f96;
```
```mermaid
graph LR
flowchart LR
A:::someclass --> B
classDef someclass fill:#f96;
```
@ -798,13 +831,13 @@ below:
**Example definition**
```
graph LR;
flowchart LR;
A-->B[AAA<span>BBB</span>];
B-->D;
class A cssClass;
```
```mermaid
graph LR;
flowchart LR;
A-->B[AAA<span>BBB</span>];
B-->D;
class A cssClass;
@ -827,14 +860,14 @@ It is possible to add icons from fontawesome.
The icons are accessed via the syntax fa:#icon class name#.
```
graph TD
flowchart TD
B["fa:fa-twitter for peace"]
B-->C[fa:fa-ban forbidden]
B-->D(fa:fa-spinner);
B-->E(A fa:fa-camera-retro perhaps?);
```
```mermaid
graph TD
flowchart TD
B["fa:fa-twitter for peace"]
B-->C[fa:fa-ban forbidden]
B-->D(fa:fa-spinner);
@ -851,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.
```
graph LR
flowchart LR
A[Hard edge] -->|Link text| B(Round edge)
B --> C{Decision}
C -->|One| D[Result one]
@ -859,7 +892,7 @@ graph LR
```
```mermaid
graph LR
flowchart LR
A[Hard edge] -->|Link text| B(Round edge)
B --> C{Decision}
C -->|One| D[Result one]

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 KiB

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="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="theme.css"> <script src="//cdn.jsdelivr.net/npm/mermaid@8.9.1/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>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){

View File

@ -9,6 +9,8 @@ They also serve as proof of concept, for the variety of things that can be built
- [GitLab](https://docs.gitlab.com/ee/user/markdown.html#diagrams-and-flowcharts) (**Native support**)
- [Azure Devops](https://docs.microsoft.com/en-us/azure/devops/project/wiki/wiki-markdown-guidance?view=azure-devops#add-mermaid-diagrams-to-a-wiki-page) (**Native support**)
- [Tuleap](https://docs.tuleap.org/user-guide/writing-in-tuleap.html#graphs) (**Native support**)
- [Joplin](https://joplinapp.org) (**Native support**)
- [GitHub](https://github.com)
- [Github action: Compile mermaid to image](https://github.com/neenjaw/compile-mermaid-markdown-action)
- [svg-generator](https://github.com/SimonKenyonShepard/mermaidjs-github-svg-generator)
@ -110,6 +112,10 @@ They also serve as proof of concept, for the variety of things that can be built
- [iodide-mermaid-plugin](https://github.com/iodide-project/iodide-mermaid-plugin)
- [Google docs](https://docs.google.com/)
- [Mermaid plugin for google docs](https://workspace.google.com/marketplace/app/mermaid/636321283856)
- [Podlite](https://github.com/zag/podlite-desktop)
- [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
@ -124,19 +130,27 @@ They also serve as proof of concept, for the variety of things that can be built
- [Type Doc](https://typedoc.org/)
- [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)
- [Codedoc](https://codedoc.cc/)
- [codedoc-mermaid-plugin](https://www.npmjs.com/package/codedoc-mermaid-plugin)
## Chrome Extensions
## Browser Extensions
## Browser Extensions
| Name | Chrome Web Store | Firefox Add-ons | Opera | Edge | Source/Repository |
| -- | -- | -- | -- | -- | -- |
| 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) | -|
| Diagram Tab| -| - | - | - | [🐙🔗](https://github.com/khafast/diagramtab) |
| 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)|
| 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) | - |- | - | - |
| Mermaid Diagrams | [🎡🔗](https://chrome.google.com/webstore/detail/mermaid-diagrams/phfcghedmopjadpojhmmaffjmfiakfil) | - | - | - | - |
|Mermaid Markdown | [🎡🔗](https://chrome.google.com/webstore/detail/mermaid-markdown/mboeoikjijmjcjgpccghbcoegikliijg) | - | - | - | - |
| Monkeys | [🎡🔗](https://chrome.google.com/webstore/detail/monkeys-mermaid-for-githu/cplfdpoajbclbgphaphphcldamfkjlgi) | - | - | - | - |
- [Mermaid Diagrams](https://chrome.google.com/webstore/detail/mermaid-diagrams/phfcghedmopjadpojhmmaffjmfiakfil)
- [GitHub + Mermaid](https://chrome.google.com/webstore/detail/github-%2B-mermaid/goiiopgdnkogdbjmncgedmgpoajilohe)
- [Mermaid Markdown](https://chrome.google.com/webstore/detail/mermaid-markdown/mboeoikjijmjcjgpccghbcoegikliijg)
- [Monkeys](https://chrome.google.com/webstore/detail/monkeys-mermaid-for-githu/cplfdpoajbclbgphaphphcldamfkjlgi)
- [Asciidoctor Live Preview](https://chrome.google.com/webstore/detail/asciidoctorjs-live-previe/iaalpfgpbocpdfblpnhhgllgbdbchmia) __works in the new IE as well__
- [Chrome Diagrammer](https://chrome.google.com/webstore/detail/chrome-diagrammer/bkpbgjmkomfoakfklcjeoegkklgjnnpk)
- [Diagram Tab](https://github.com/khafast/diagramtab)
## Other
- [Jekyll](https://jekyllrb.com/)
- [jekyll-mermaid](https://rubygems.org/gems/jekyll-mermaid)
- [jekyll-mermaid-diagrams](https://github.com/fuzhibo/jekyll-mermaid-diagrams)

BIN
docs/landing/class.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

BIN
docs/landing/cover.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
docs/landing/er.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
docs/landing/flowchart.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
docs/landing/gantt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

233
docs/landing/index.html Normal file
View File

@ -0,0 +1,233 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>
The Official Guide to Mermaid.js
</title>
<meta name="description" content="Landing page for the book The Official Guide to Mermaid.js: Create complex diagrams and beautiful flowcharts easily using text and code" />
<meta name="keywords" content="book, guide, mermaid, flowcharts, sequence diagrams, class diagrams, state diagrams, pie charts, Entity Relationship Diagrams, User Journey Diagrams, Requirement Diagrams, Gantt Charts" />
<meta name="author" content="Knut Sveidqvist, Ashish Jain" />
<link rel="stylesheet" href="https://unpkg.com/tailwindcss/dist/tailwind.min.css" />
<!--Replace with your tailwind.css once created-->
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700" rel="stylesheet" />
<!-- Define your gradient here - use online tools to find a gradient matching your branding-->
<style>
.gradient {
background: linear-gradient(90deg, #7557C9 0%, #f4f4f4 100%);
}
.p-shadow {
text-shadow: #7557c9 0px 0px 5px
}
</style>
</head>
<body class="leading-normal tracking-normal text-white gradient" style="font-family: 'Source Sans Pro', sans-serif;">
<!--Nav-->
<!--Hero-->
<div class="pt-24">
<div style="" class="container lg:px-24 max-w-5xl px-4 mx-auto flex flex-wrap flex-col md:flex-row items-center">
<!--Left Col-->
<div class="w-full md:w-1/2">
<div class="flex flex-col justify-center items-start text-center md:text-left">
<div class="flex flex-col items-center">
<p class="uppercase tracking-loose w-full p-shadow">MermaidPress</p>
<h1 class="my-4 text-5xl font-bold leading-tight p-shadow">
The Official Guide to Mermaid.js
</h1>
<p class="leading-normal text-2xl mb-8 p-shadow">
Learn to create complex diagrams and beautiful flowcharts easily using text and code using Mermaid.js.
</p>
<a href="https://www.amazon.com/Official-Guide-Mermaid-js-beautiful-flowcharts-dp-1801078025/dp/1801078025/ref=mt_other?_encoding=UTF8&me=&qid=1628153965">
<button style="background: #FFA41C;border: 1px solid #FF8F00;" class="mx-auto lg:mx-0 hover:underline text-black font-bold rounded-full my-6 py-4 px-8 shadow-lg focus:outline-none focus:shadow-outline transform transition hover:scale-105 duration-300 ease-in-out">
Purchase on Amazon
</button>
</a>
</div>
</div>
</div>
<!--Right Col-->
<div class="flex-1 md:w-3/5 py-6 text-center flex justify-end">
<img class="z-50" style="max-width: 350px" src="cover.jpg" />
</div>
</div>
</div>
<div class="relative -mt-0 lg:-mt-12">
<svg viewBox="0 0 1428 174" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g transform="translate(-2.000000, 44.000000)" fill="#FFFFFF" fill-rule="nonzero">
<path d="M0,0 C90.7283404,0.927527913 147.912752,27.187927 291.910178,59.9119003 C387.908462,81.7278826 543.605069,89.334785 759,82.7326078 C469.336065,156.254352 216.336065,153.6679 0,74.9732496" opacity="0.100000001"></path>
<path
d="M100,104.708498 C277.413333,72.2345949 426.147877,52.5246657 546.203633,45.5787101 C666.259389,38.6327546 810.524845,41.7979068 979,55.0741668 C931.069965,56.122511 810.303266,74.8455141 616.699903,111.243176 C423.096539,147.640838 250.863238,145.462612 100,104.708498 Z"
opacity="0.100000001"
></path>
<path d="M1046,51.6521276 C1130.83045,29.328812 1279.08318,17.607883 1439,40.1656806 L1439,120 C1271.17211,77.9435312 1140.17211,55.1609071 1046,51.6521276 Z" id="Path-4" opacity="0.200000003"></path>
</g>
<g transform="translate(-4.000000, 76.000000)" fill="#FFFFFF" fill-rule="nonzero">
<path
d="M0.457,34.035 C57.086,53.198 98.208,65.809 123.822,71.865 C181.454,85.495 234.295,90.29 272.033,93.459 C311.355,96.759 396.635,95.801 461.025,91.663 C486.76,90.01 518.727,86.372 556.926,80.752 C595.747,74.596 622.372,70.008 636.799,66.991 C663.913,61.324 712.501,49.503 727.605,46.128 C780.47,34.317 818.839,22.532 856.324,15.904 C922.689,4.169 955.676,2.522 1011.185,0.432 C1060.705,1.477 1097.39,3.129 1121.236,5.387 C1161.703,9.219 1208.621,17.821 1235.4,22.304 C1285.855,30.748 1354.351,47.432 1440.886,72.354 L1441.191,104.352 L1.121,104.031 L0.457,34.035 Z"
></path>
</g>
</g>
</svg>
</div>
<section class="bg-white border-b py-8">
<div class="container max-w-5xl mx-auto m-8">
<h2 class="w-full my-2 text-5xl font-bold leading-tight text-center text-gray-800">
Get up to speed with using Mermaid diagrams along with real-world examples and expert tips from the authors to facilitate a seamless development workflow
</h2>
<div class="w-full mb-4">
<div class="h-1 mx-auto gradient w-64 opacity-25 my-0 py-0 rounded-t"></div>
</div>
<div class="flex flex-wrap">
<div class="w-full sm:w-1/2 p-6 flex items-center">
<p class="text-3xl text-gray-800 font-normal leading-none mb-3">
Flowcharts is a diagram type that visualizes a process or an algorithm by showing the steps in order, as well as the different paths the execution can take.
</p>
</div>
<div class="w-full sm:w-1/2 p-6 flex justify-center items-center">
<img class="z-50" src="flowchart.png" />
</div>
</div>
<div class="flex flex-wrap flex-col-reverse sm:flex-row flex justify-center items-center">
<div class="w-full sm:w-1/2 p-6 mt-6 ">
<img class="z-50 w-full" style="" src="sequence-diagram.png" />
</div>
<div class="w-full sm:w-1/2 p-6 mt-6">
<div class="align-middle flex items-center">
<p class="text-3xl text-gray-800 font-normal leading-none mb-3">
Sequence diagrams lets you model and visualize interactions between different actors or objects in a system, as well as the order of those interactions
</p>
</div>
</div>
</div>
<div class="flex flex-wrap">
<div class="w-full sm:w-1/2 p-6 flex items-center">
<p class="text-3xl text-gray-800 font-normal leading-none mb-3">
A class diagram is a graphical representation that is used to visualize and describe
an object-oriented system.
</p>
</div>
<div class="w-full sm:w-1/2 p-6 flex justify-center items-center">
<img class="z-50" style="" src="class.png" />
</div>
</div>
<div class="flex flex-wrap flex-col-reverse sm:flex-row flex justify-center items-center">
<div class="w-full sm:w-1/2 p-6 mt-6 ">
<img class="z-50 w-full" style="" src="er.png" />
</div>
<div class="w-full sm:w-1/2 p-6 mt-6">
<div class="align-middle flex items-center">
<p class="text-3xl text-gray-800 font-normal leading-none mb-3">
An entity-relationship diagram is a graphical representation that is used to visualize the different types of entities that exist within a system.
</p>
</div>
</div>
</div>
<div class="flex flex-wrap">
<div class="w-full sm:w-1/2 p-6 flex items-center">
<p class="text-3xl text-gray-800 font-normal leading-none mb-3">
Use State diagrams to model and document state machines, an abstract way of representing a system or an algorithm.
</p>
</div>
<div class="w-full sm:w-1/2 p-6 flex justify-center items-center">
<img class="z-50" style="" src="state.png" />
</div>
</div>
<div class="flex flex-wrap flex-col-reverse sm:flex-row flex justify-center items-center">
<div class="w-full sm:w-1/2 p-6 mt-6 ">
<img class="z-50 w-full" style="" src="gantt.png" />
</div>
<div class="w-full sm:w-1/2 p-6 mt-6">
<div class="align-middle flex items-center">
<p class="text-3xl text-gray-800 font-normal leading-none mb-3">
A Gantt chart is a graphical representation that is used to visualize and describe tasks (events or activities) over time.
</p>
</div>
</div>
</div>
</div>
<p class="text-3xl text-gray-800 font-normal leading-none mt-3 text-center">These were a few of the diagrams supported by Mermaid.</p>
</section>
<section class="bg-gray-100 border-b py-8">
<div class="container mx-auto flex flex-wrap max-w-5xl mx-auto m-8 pt-4 pb-12 px-8">
<h1 class="w-full my-2 text-5xl font-bold leading-tight text-center text-gray-800">
Book description
</h1>
<div class="w-full mb-4">
<p class="text-black mb-4">Mermaid lets you represent diagrams using text and code which simplifies the maintenance of complex diagrams. This is a great option for developers as theyre more familiar with code, rather than special tools for generating diagrams. Besides, diagrams in code simplify maintenance and ensure that the code is supported by version control systems. In some cases, Mermaid makes refactoring support for name changes possible while also enabling team collaboration for review distribution and updates.</p>
<p class="text-black mb-4">Developers working with any system will be able to put their knowledge to work with this practical guide to using Mermaid for documentation. The book is also a great reference for looking up the syntax for specific diagrams when authoring diagrams.</p>
<p class="text-black mb-4">Youll start by getting up to speed with the importance of accurate and visual documentation. Next, the book introduces Mermaid and establishes how to use it to create effective documentation. By using different tools, editors, or a custom documentation platform, youll also learn how to use Mermaid syntax for various diagrams. Later chapters cover advanced configuration settings and theme options to manipulate your diagram as per your needs.</p>
<p class="text-black mb-4">By the end of this Mermaid book, youll have become well-versed with the different types of Mermaid diagrams and how they can be used in your workflows.</p>
</div>
</section>
<section class="bg-white py-8">
<div class="container mx-auto px-2 pt-4 pb-12 text-gray-800">
<h1 class="w-full my-2 text-5xl font-bold leading-tight text-center text-gray-800">
What you will learn
</h1>
<div class="w-full mb-4">
<div class="h-1 mx-auto gradient w-64 opacity-25 my-0 py-0 rounded-t"></div>
</div>
<div class="flex flex-col sm:flex-row justify-center items-center pt-12 my-12 sm:my-4">
<div class="flex flex-col mx-4 rounded-lg bg-white mt-4 sm:-mt-6 shadow-lg z-10">
<div class="flex-1 bg-white rounded-t rounded-b-none overflow-hidden shadow">
<ul class="w-full text-base font-bold px-4">
<li class="border-b py-4 px-4">Understand good and bad documentation, and the art of effective documentation</li>
<li class="border-b py-4 px-4">Become well-versed with maintaining complex diagrams with ease</li>
<li class="border-b py-4 px-4">Learn how to set up a custom documentation system</li>
<li class="border-b py-4 px-4">Learn how to implement Mermaid diagrams in your workflows</li>
<li class="border-b py-4 px-4">Understand how to set up themes for a Mermaid diagram for an entire site</li>
<li class="border-b py-4 px-4">Discover how to draw different types of diagrams such as flowcharts, class diagrams, Gantt charts, and more</li>
</ul>
</div>
</div>
</div>
</div>
</section>
<!-- Change the colour #f8fafc to match the previous section colour -->
<svg class="wave-top" viewBox="0 0 1439 147" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g transform="translate(-1.000000, -14.000000)" fill-rule="nonzero">
<g class="wave" fill="#f8fafc">
<path
d="M1440,84 C1383.555,64.3 1342.555,51.3 1317,45 C1259.5,30.824 1206.707,25.526 1169,22 C1129.711,18.326 1044.426,18.475 980,22 C954.25,23.409 922.25,26.742 884,32 C845.122,37.787 818.455,42.121 804,45 C776.833,50.41 728.136,61.77 713,65 C660.023,76.309 621.544,87.729 584,94 C517.525,105.104 484.525,106.438 429,108 C379.49,106.484 342.823,104.484 319,102 C278.571,97.783 231.737,88.736 205,84 C154.629,75.076 86.296,57.743 0,32 L0,0 L1440,0 L1440,84 Z"
></path>
</g>
<g transform="translate(1.000000, 15.000000)" fill="#FFFFFF">
<g transform="translate(719.500000, 68.500000) rotate(-180.000000) translate(-719.500000, -68.500000) ">
<path d="M0,0 C90.7283404,0.927527913 147.912752,27.187927 291.910178,59.9119003 C387.908462,81.7278826 543.605069,89.334785 759,82.7326078 C469.336065,156.254352 216.336065,153.6679 0,74.9732496" opacity="0.100000001"></path>
<path
d="M100,104.708498 C277.413333,72.2345949 426.147877,52.5246657 546.203633,45.5787101 C666.259389,38.6327546 810.524845,41.7979068 979,55.0741668 C931.069965,56.122511 810.303266,74.8455141 616.699903,111.243176 C423.096539,147.640838 250.863238,145.462612 100,104.708498 Z"
opacity="0.100000001"
></path>
<path d="M1046,51.6521276 C1130.83045,29.328812 1279.08318,17.607883 1439,40.1656806 L1439,120 C1271.17211,77.9435312 1140.17211,55.1609071 1046,51.6521276 Z" opacity="0.200000003"></path>
</g>
</g>
</g>
</g>
</svg>
<section class="container mx-auto text-center py-6 mb-12">
<h1 class="w-full my-2 text-5xl font-bold leading-tight text-center text-white p-shadow">
Purchase The Official Guide to Mermaid.js
</h1>
<div class="w-full mb-4">
<div class="h-1 mx-auto bg-white w-1/6 opacity-25 my-0 py-0 rounded-t"></div>
</div>
<h3 class="my-4 text-3xl leading-tight">
<p class="mb-4 p-shadow">Written by Knut Sveidqvist and Ashish Jain.</p>
<p class="p-shadow">Knut is the creator of Mermaid and both authors are active core team members of the Mermaid open-source project.</p>
</h3>
<a href="https://www.amazon.com/Official-Guide-Mermaid-js-beautiful-flowcharts-dp-1801078025/dp/1801078025/ref=mt_other?_encoding=UTF8&me=&qid=1628153965">
<button style="background: #FFA41C;border: 1px solid #FF8F00;" class="mx-auto lg:mx-0 hover:underline bg-white text-gray-800 font-bold rounded-full my-6 py-4 px-8 shadow-lg focus:outline-none focus:shadow-outline transform transition hover:scale-105 duration-300 ease-in-out">
Purchase Now on Amazon
</button>
</a>
</section>
<!--Footer-->
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
docs/landing/state.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -1,41 +1,59 @@
# A Mermaid User-Guide for Beginners
Creating diagrams and charts using mermaid code is simple.
Mermaid is composed of three parts, Deployment, Syntax and Configuration.
This section talks about the different ways to deploy Mermaid. Learning the [Syntax](./n00b-syntaxReference.md) ahead of time would be more helpful to the beginner.
> Generally the live editor is enough for most general uses of mermaid, and is a good place to start learning.
>The live editor is enough for most general uses of mermaid
**Absolute beginners are recommended to view the Video [Tutorials](./Tutorials.md) on the Live Editor, to gain a better understanding of mermaid.**
## Four ways of using mermaid:
1. Using the mermaid [Live Editor](https://mermaid-js.github.io/mermaid-live-editor/).
- Learning the [Syntax](./n00b-syntaxReference) would be helpful.
2. Using [mermaid plugins](./integrations.md) with programs you are familiar with.
3. Hosting mermaid on a webpage, with an absolute link.
4. Downloading mermaid and hosting it on your Web Page.
3. Calling the Mermaid Javascript API.
4. Deploying Mermaid as a dependency.
**Note: It is our recommendation that you review all approaches, and choose the one that is best for your project.**
>More in depth information can be found on [Usage](./usage.md).
> More in depth information can be found on [Usage](./usage.md).
## 1. Using [The Live Editor](https://mermaidjs.github.io/mermaid-live-editor).
## 1. Using [The Live Editor](https://mermaidjs.github.io/mermaid-live-editor/edit).
![Flowchart](./img/Live-Editor-Usage.png)
![EditingProcess](./img/Editing-process.png)
In the `Code` section one can write or edit raw mermaid code, and instantly `Preview` the rendered result on the panel beside it.
![Flowchart](./img/DiagramDefinition.png)
The `Configuration` Section is for changing the appearance and behavior of mermaid diagrams. 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](Setup.md) page.
**Saving a Diagram:**
You may choose any of the methods below, to save it
![Code,Config and Preview](./img/Code-Preview-Config.png)
### Editing History
Your code will be autosaved every minute into the Timeline tab of History, having the most recent 30 items.
You can also manually save code by clicking the Save icon in History section which can be accessed in the Saved tab. This is stored only in the browser storage.
### Saving a Diagram:
You may choose any of the methods below, to save it
**We recommend that you save your diagram code on top of any method you choose, in order to make edits and modifications further down the line.**
![Flowchart](./img/Live-Editor-Choices.png)
**Configuration**
### Editing your diagrams
*The Mermaid configuration* is for configuring the appearance and behavior of mermaid diagrams. 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](Setup.md) page.
Editing is as easy as pasting your **Diagram code**, into the `code` section of the `Live Editor`.
![Flowchart](./img/Configuration.png)
### Loading from Gists
The Gist you create should have a code.mmd file and optionally a config.json. [Example](https://gist.github.com/sidharthv96/6268a23e673a533dcb198f241fd7012a)
To load a gist into the Editor, you can use https://mermaid-js.github.io/mermaid-live-editor/edit?gist=https://gist.github.com/sidharthv96/6268a23e673a533dcb198f241fd7012a
and to View, https://mermaid-js.github.io/mermaid-live-editor/view?gist=https://gist.github.com/sidharthv96/6268a23e673a533dcb198f241fd7012a
## 2. Using Mermaid Plugins:
@ -43,32 +61,29 @@ Using plug-ins you can generate mermaid diagrams from within popular application
**This is covered in greater detail in the [Usage section](usage.md)**
## 3. Mermaid with Inline JavaScript
## 3. Calling the Javascript API
This method can be used with any common web server. Apache, IIS, nginx, node express [...], you pick your favourite.
This method can be used with any common web server. Apache, IIS, nginx, node express, you are free to choose.
You will need a text editting tool like Notepad++, to generate an html file. It is then deployed by a web browser (such as Firefox, Chrome, Safari, but not Internet Explorer).
You will also need a text editting tool like Notepad++, to generate an html file. It is then deployed by a web browser (such as Firefox, Chrome, Safari, but not Internet Explorer).
Just create an HTML file locally and open it using a desired browser.
The API works by pulling rendering instructions from a source from `mermaid.js` to render diagrams in the page.
### Written in the html `<body>` section of the web page.
### Requirements for the Mermaid API.
When writing the html file, we give the web browser three instructions inside the html code:
a. A reference for fetching the online mermaid renderer, which is written in Javascript.
a. A reference for fetching the online mermaid renderer, through the `mermaid.js` or `mermaid.min.js`.
b. The mermaid code for the diagram we want to create.
c. The `mermaid.initialize()` call to start the rendering process.
## Requirements for mermaidAPI to render a diagram:
c. The `mermaid.initialize()` call, which can dictate the appreance of diagrams and also start the rendering process .
**a. A reference to the external CDN in a `<script src>` tag, or a reference to mermaid.js as a separate file.:**
```html
<body>
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
</body>
```
@ -76,23 +91,24 @@ c. The `mermaid.initialize()` call to start the rendering process.
```html
<body>
Here is a mermaid diagram:
<div class="mermaid">
graph TD
A[Client] --> B[Load Balancer]
B --> C[Server01]
B --> D[Server02]
</div>
Here is a mermaid diagram:
<div class="mermaid">
graph TD A[Client] --> B[Load Balancer] B --> C[Server01] B --> D[Server02]
</div>
</body>
```
**Notes**: every mermaid chart/graph/diagram definition, has to have separate `<div>` tags.
**c. The `mermaid.initialize()` call.**
`mermaid.initialize()` calls take all the definitions contained in `<div class="mermaid">` tags it can find in the html body and render. Example:
`mermaid.initialize()` calls take all the definitions contained in `<div class="mermaid">` tags it can find in the html body and renders them into diagrams. Example:
```html
<body>
<script>mermaid.initialize({startOnLoad:true});</script>
<script>
mermaid.initialize({ startOnLoad: true });
</script>
</body>
```
@ -101,78 +117,74 @@ Mermaid rendering is initalized with `mermaid.initialize()`.You can place `merma
`startOnLoad` is one of the parameters that can be defined by `mermaid.initialize()`
| Parameter | Description | Type | Values |
| --------- | --------------- | ------ | ---------------------------------------------------- |
|startOnLoad| Toggle for Rendering upon loading | Boolean | true, false |
| Parameter | Description | Type | Values |
| ----------- | --------------------------------- | ------- | ----------- |
| startOnLoad | Toggle for Rendering upon loading | Boolean | true, false |
### Working Examples
**Here is a full working example of the mermaidAPI being called through the CDN:**
```html
<html>
<body>
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
<script>mermaid.initialize({startOnLoad:true});</script>
<body>
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
<script>
mermaid.initialize({ startOnLoad: true });
</script>
Here is one mermaid diagram:
<div class="mermaid">
graph TD
A[Client] --> B[Load Balancer]
B --> C[Server1]
B --> D[Server2]
</div>
Here is one mermaid diagram:
<div class="mermaid">
graph TD A[Client] --> B[Load Balancer] B --> C[Server1] B --> D[Server2]
</div>
And here is another:
<div class="mermaid">
graph TD
A[Client] -->|tcp_123| B(Load Balancer)
B -->|tcp_456| C[Server1]
B -->|tcp_456| D[Server2]
</div>
</body>
And here is another:
<div class="mermaid">
graph TD A[Client] -->|tcp_123| B(Load Balancer) B -->|tcp_456| C[Server1] B
-->|tcp_456| D[Server2]
</div>
</body>
</html>
```
**Another Option:**
In this example mermaid.js is referenced in `src` as a separate JavaScript file, in an example Path.
In this example mermaid.js is referenced in `src` as a separate JavaScript file, in an example Path.
```html
<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="The\Path\In\Your\Package\mermaid.js"></script>
<script>mermaid.initialize({startOnLoad:true});</script>
</body>
<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="The\Path\In\Your\Package\mermaid.js"></script>
<script>
mermaid.initialize({ startOnLoad: true });
</script>
</body>
</html>
```
---
## 4. Adding Mermaid as a dependency.
1. install node v10 or 12, which would have npm
1. install node v16, which would have npm
2. download yarn using npm by entering the command below:
npm install -g yarn
npm install -g yarn
3. After yarn installs, enter the following command:
yarn add mermaid
4. To add Mermaid as a Dev Dependency
yarn add --dev mermaid
yarn add mermaid
4. To add Mermaid as a Dev Dependency
yarn add --dev mermaid
**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. Nowadays we can place it in the `<body>` as seen above. Older parts of the documentation frequently reflects the previous way which still works.
- In early versions of mermaid, the `<script src>` tag was invoked in the `<head>` part of the web page. Nowadays we can place it in the `<body>` as seen above. Older parts of the documentation frequently reflects the previous way which still works.

View File

@ -2,27 +2,27 @@
**Explaining with a Diagram**
A picture is worth a thousand words, a good diagram is certainly worth more.
A picture is worth a thousand words, a good diagram is undoubtedly worth more. They make understanding easier.
## Creating and Maintaining Diagrams
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.
Anyone who has used Visio, or (God Forbid) Excel to make a Gantt Chart, knows how hard it is to create, edit and maintain good visualizations.
Diagrams/Charts are both very important but also become obsolete/inaccurate very fast. This catch-22 hobbles the productivity of teams.
Diagrams/Charts are significant but also become obsolete/inaccurate very fast. This catch-22 hobbles the productivity of teams.
# Doc Rot in Diagrams
Doc-Rot kills diagrams as quickly as it does text, but it takes hours in a desktop application to produce a diagram.
mermaid seeks to change that. mermaid creates diagrams using markdown inspired syntax. The process is quicker, less complicated and more convenient way of going from concept to visualization
Mermaid seeks to change using markdown-inspired syntax. The process is a quicker, less complicated, and more convenient way of going from concept to visualization.
This is a relatively straightforward solution to a major hurdle in software teams.
It is a relatively straightforward solution to a significant hurdle with the software teams.
# Definition of Terms/ Dictionary
**Mermaid text definitions can be saved for later reuse and editing.**
>These are the Mermaid diagram deffinitions inside `<div>` tags, with the `class=mermaid`.
>These are the Mermaid diagram definitions inside `<div>` tags, with the `class=mermaid`.
```html
<div class="mermaid">
@ -35,33 +35,33 @@ This is a relatively straightforward solution to a major hurdle in software team
**render**
>This is the core function of the Mermaid API, it reads all the `Mermaid Definitions` inside `div` tags and returns an SVG file, based on the definitions.
>This is the core function of the Mermaid API. It reads all the `Mermaid Definitions` inside `div` tags and returns an SVG file, based on the definition.
**Nodes**
>These are the boxes that contain text or otherwise discrete pieces of each diagram, separated generally by arrows, except for Gantt Charts and User Journey Diagrams. They will be referred to often in the instructions. Read for Diagram Specific [Syntax](./n00b-syntaxReference)
>These are the boxes that contain text or otherwise discrete pieces of each diagram, separated generally by arrows, except for Gantt Charts and User Journey Diagrams. They will be referred often in the instructions. Read for Diagram Specific [Syntax](./n00b-syntaxReference)
## Advantages of Using Mermaid
## Advantages of using Mermaid
- Ease of generate, modify and render diagrams, when you make
- Ease to generate, modify and render diagrams when you make them.
- The number of integrations and plugins it has.
- It can be added to your or your company's website.
- You can add it to your or companies website.
- Diagrams can be created through comments like this in a script:
## The catch-22 of Diagrams and Charts:
**Diagramming and charting is a gigantic waste of developer time, but not having diagrams ruins productivity.**
**Diagramming and charting is a large waste of developer's time, but not having diagrams ruins productivity.**
mermaid solves this by cutting the time, effort and tooling that is required to create diagrams and charts.
Mermaid solves this by reducing the timeand effort required to create diagrams and charts.
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.
Because, the text base for the diagrams allows it to be updated easily. Also, it can be made part of production scripts (and other pieces of code). So less time is spent on documenting, as a separate task.
## Catching up with Development
Being based on markdown, mermaid can be used, not only by accomplished front-end developers, but by most computer savvy people to render 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.
Being based on markdown, Mermaid can be used, not only by accomplished front-end developers, but by most computer savvy people to render 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 available in the internet.
## Mermaid is for everyone.
Video [Tutorials](https://mermaid-js.github.io/mermaid/#/./Tutorials) are also available for the mermaid [live editor](https://mermaid-js.github.io/mermaid-live-editor/).

View File

@ -1,33 +1,87 @@
## Diagram syntax
# Diagram Syntax
Mermaid's syntax is used to create diagrams. You'll find that it is not too tricky and can be learned in a day. The next sections dive deep into the syntax of each diagram type.
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.
Syntax, together with Deployment and Configuration constitute the whole of Mermaid.
Below is a list of diagram types supported by mermaid and how they can be defined.
Diagram Examples can be found in the [Mermaid Live Editor](https://mermaid-js.github.io/mermaid-live-editor), it is also a great practice area.
## Syntax Structure
One would notice that all **Diagrams definitions begin** with a declaration of the **diagram type**, followed by the definitions of the diagram and its contents. This declaration notifies the parser which kind of diagram the code is supposed to generate.
**Example** : The code below is for an Entity Relationship Diagram, specified by the `erDiagram` declaration. What follows is the definition of the different `Entities` represented in it.
## mermaid tag
These Diagram Definitions can be entered within a \<div class=mermaid> tag.
like so :
```html
<div class="mermaid">
graph LR
A --- B
B-->C[fa:fa-ban forbidden]
B-->D(fa:fa-spinner);
</div>
```
## Mermaid Live Editor
You can proofread or render and download your definitions in real-time with the [Mermaid Live Editor](https://mermaid-js.github.io/mermaid-live-editor).
This would then offer you the following choices to download the diagram:
![Flowchart](./img/DownloadChoices.png)
**Note:** Copying the markdown will allow you to link to your unique diagram from anywhere online.
## Directives:
[Directives](./directives.md) allows the limited reconfiguration of a diagram just before it is rendered. It can alter the font style, color and other aesthetic aspects of the diagram.
## Theme Creation:
Mermaid allows you to change [Themes](./theming.md). This is also done using [Directives](./directives.md).
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"
```
```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"
```
The [Getting Started](./n00b-gettingStarted.md) section can also provide some practical examples of mermaid syntax.
## Diagram Breaking
One should **beware the use of some words or symbols** that can break diagrams. These words or symbols are few and often only affect specific types of diagrams. The table below will continuously be updated.
| Diagram Breakers | Reason |Solution|
| --- | --- |---|
| **Comments** | | |
|[`%%{``}%%`](https://github.com/mermaid-js/mermaid/issues/1968) | Similar to [Directives](./directives.md) confuses the renderer.|In comments using `%%`, avoid using "{}".|
| **Flow-Charts** | | |
|'end' | The word "End" can cause Flowcharts and Sequence diagrams to break | Wrap them in quotation marks to prevent breakage.|
| [Nodes inside Nodes](https://mermaid-js.github.io/mermaid/#/flowchart?id=special-characters-that-break-syntax)| Mermaid gets confused with nested shapes | wrap them in quotation marks to prevent breaking|
### Mermaid Live Editor
Now, that you've seen what you should not add to your diagrams, you can play around with them in the [Mermaid Live Editor](https://mermaid-js.github.io/mermaid-live-editor).
# Configuration
Configuration is the third part of Mermaid, after deployment and syntax. It deals with the different ways that Mermaid can be customized across different deployments.
If you are interested in altering and customizing your Mermaid Diagrams, you will find the methods and values available for [Configuration](./Setup.md) here. It includes themes
This section will introduce the different methods of configuring of the behaviors and apperances of Mermaid Diagrams.
The Following are the most commonly used methods, and are all tied to Mermaid [Deployment](./n00b-gettingStarted.md) methods.
### Configuration Section in the [Live Editor](./Live-Editor.md).
Here you can edit certain values to change the behavior and appearance of the diagram.
### [The initialize() call](https://mermaid-js.github.io/mermaid/#/n00b-gettingStarted?id=_3-calling-the-javascript-api),
Used when Mermaid is called via an API, or through a `<script>` tag.
### [Directives](./directives.md),
Allows for the limited reconfiguration of a diagram just before it is rendered. It can alter the font style, color and other aesthetic aspects of the diagram. you can pass a directive alongside your defintion inside `%%{ }%%`, either above or below your diagram defintion.
### [Theme Manipulation](./theming.md):
An application of using Directives to change [Themes](./theming.md). `Theme` is an value within mermaid's configuration that dictates the color scheme for diagrams.

View File

@ -2,7 +2,7 @@
**Edit this Page** [![N|Solid](img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/requirementDiagram.md)
> A Requirement diagram provides a visualization for requirements and their connections, to each other and other documented elements. The modeling specs follow those defined by SysML v1.6.
> A Requirement diagram provides a visualization for requirements and their connections, to each other and other documented elements. The modeling specs follow those defined by SysML v1.6.
Rendering requirements is straightforward.
@ -63,9 +63,10 @@ A requirement definition contains a requirement type, name, id, text, risk, and
Type, risk, and method are enumerations defined in SysML.
| Keyword | Options |
|---|---|
| Type | requirement, functionalRequirement, interfaceRequirement, performanceRequirement, physicalRequirement, designConstraint |
| Risk | Low, Medium, High |
| VerifcationMethod | Analysis, Inspection, Test, Demonstration |
| Risk | Low, Medium, High |
| VerifcationMethod | Analysis, Inspection, Test, Demonstration |
### Element
An element definition contains an element name, type, and document reference. These three are all user defined. The element feature is intended to be lightweight but allow requirements to be connected to portions of other documents.
@ -87,7 +88,7 @@ Each follows the definition format of
{name of source} - <type> -> {name of destination}
```
or
or
```
{name of destination} <- <type> - {name of source}
@ -169,5 +170,5 @@ This example uses all features of the diagram.
test_req4 - derives -> test_req5
test_req5 - refines -> test_req6
test_entity3 - verifies -> test_req5
test_req <- copies - test_entity2 </div>
```
test_req <- copies - test_entity2
```

View File

@ -566,7 +566,7 @@ text.actor {
Is it possible to adjust the margins for rendering the sequence diagram.
This is done by defining `mermaid.sequenceConfig` or by the CLI to use a json file with the configuration.
How to use the CLI is described in the [mermaidCLI](mermaidCLI.html) page.
How to use the CLI is described in the [mermaidCLI](mermaidCLI) page.
`mermaid.sequenceConfig` can be set to a JSON string with config parameters or the corresponding object.
```javascript

View File

@ -228,6 +228,28 @@ stateDiagram-v2
*You can not define transitions between internal states belonging to different composite states*
## Choice
Sometimes you need to model a choice between two or more paths, you can do so using &lt;&lt;choice&gt;&gt;.
```
stateDiagram-v2
state if_state <<choice>>
[*] --> IsPositive
IsPositive --> if_state
if_state --> False: if n < 0
if_state --> True : if n >= 0
```
```mermaid
stateDiagram-v2
state if_state <<choice>>
[*] --> IsPositive
IsPositive --> if_state
if_state --> False: if n < 0
if_state --> True : if n >= 0
```
## Forks
It is possible to specify a fork in the diagram using &lt;&lt;fork&gt;&gt; &lt;&lt;join&gt;&gt;.
@ -332,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 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

@ -461,7 +461,7 @@ classDiagram
### Gantt
```
gantt
dateFormat :YYYY-MM-DD
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
@ -491,7 +491,7 @@ gantt
```mermaid
gantt
dateFormat :YYYY-MM-DD
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

View File

@ -4,7 +4,7 @@
Mermaid is a Javascript tool that makes use of a markdown based syntax to render customizable diagrams, charts and visualizations.
Diagrams can be re-rendered/modified by modifying their descriptions.
Diagrams can be re-rendered/modified by modifying their descriptions.
### CDN
@ -16,14 +16,14 @@ Please note that you can switch versions through the dropdown box at the top rig
For the majority of users, Using the [Live Editor](https://mermaid-js.github.io/mermaid-live-editor/) would be sufficient, however you may also opt to deploy mermaid as a dependency or using the [Mermaid API](./Setup.md).
We have compiled some Video [Tutorials](./Tutorials.md) on how to use the mermaid Live Editor.
We have compiled some Video [Tutorials](./Tutorials.md) on how to use the mermaid Live Editor.
**Installing and Hosting Mermaid on a Webpage**
**Using the npm package**
```
1.You will need to install node v10 or 12, which would have npm.
1.You will need to install node v16, which would have npm.
2. download yarn using npm.

View File

@ -1,13 +1,14 @@
const path = require('path');
module.exports = {
testEnvironment: 'jsdom',
transform: {
'^.+\\.jsx?$': './transformer.js',
'^.+\\.jison$': path.resolve(__dirname, './jisonTransformer.js')
'^.+\\.jison$': path.resolve(__dirname, './jisonTransformer.js'),
},
transformIgnorePatterns: ['/node_modules/(?!dagre-d3-renderer/lib).*\\.js'],
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 { getOptions } = require('loader-utils')
const { Generator } = require('jison');
const { getOptions } = require('loader-utils');
module.exports = function jisonLoader (source) {
return new Generator(source, getOptions(this)).generate()
}
module.exports = function jisonLoader(source) {
return new Generator(source, getOptions(this)).generate();
};

View File

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

View File

@ -1,6 +1,6 @@
{
"name": "mermaid",
"version": "8.9.2",
"version": "8.12.0",
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
"main": "dist/mermaid.core.js",
"keywords": [
@ -13,19 +13,18 @@
"git graph"
],
"scripts": {
"build:development": "webpack --progress --colors",
"build:production": "yarn build:development -p --config webpack.config.prod.babel.js",
"build:development": "webpack --progress --color",
"build:production": "yarn build:development --mode production --config webpack.config.prod.babel.js",
"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",
"build:watch": "yarn build --watch",
"minify": "minify ./dist/mermaid.js > ./dist/mermaid.min.js",
"release": "yarn build",
"lint": "eslint src",
"e2e:depr": "yarn lint && jest e2e --config e2e/jest.config.js",
"cypress": "percy exec -- cypress run",
"e2e": "start-server-and-test dev http://localhost:9000/ cypress",
"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:watch": "jest --watch src",
"prepublishOnly": "yarn build && yarn test",
@ -49,60 +48,49 @@
},
"dependencies": {
"@braintree/sanitize-url": "^3.1.0",
"d3": "^5.7.0",
"dagre": "^0.8.4",
"d3": "^7.0.0",
"dagre": "^0.8.5",
"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",
"stylis": "^3.5.2"
"dompurify": "2.3.1",
"graphlib": "^2.1.8",
"khroma": "^1.4.1",
"moment-mini": "^2.24.0",
"stylis": "^4.0.10"
},
"devDependencies": {
"@babel/core": "^7.2.2",
"@babel/preset-env": "^7.8.4",
"@babel/register": "^7.0.0",
"@percy/cypress": "*",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^24.9.0",
"babel-loader": "^8.0.4",
"@babel/core": "^7.14.6",
"@babel/eslint-parser": "^7.14.7",
"@babel/preset-env": "^7.14.7",
"@babel/register": "^7.14.5",
"@percy/cli": "^1.0.0-beta.58",
"@percy/cypress": "^3.1.0",
"@percy/migrate": "^0.11.0",
"babel-jest": "^27.0.6",
"babel-loader": "^8.2.2",
"coveralls": "^3.0.2",
"css-loader": "^2.0.1",
"css-to-string-loader": "^0.1.3",
"cypress": "4.0.1",
"documentation": "^12.0.1",
"eslint": "^6.3.0",
"eslint-config-prettier": "^6.3.0",
"eslint-plugin-prettier": "^3.1.0",
"husky": "^1.2.1",
"cypress": "8.1.0",
"documentation": "13.2.0",
"eslint": "^7.30.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^3.4.0",
"husky": "^7.0.1",
"identity-obj-proxy": "^3.0.0",
"jest": "^24.9.0",
"jest": "^27.0.6",
"jison": "^0.4.18",
"js-base64": "3.6.1",
"moment": "^2.23.0",
"node-sass": "^5.0.0",
"prettier": "^1.18.2",
"puppeteer": "^1.17.0",
"sass-loader": "^7.1.0",
"start-server-and-test": "^1.10.6",
"terser-webpack-plugin": "^2.2.2",
"prettier": "^2.3.2",
"start-server-and-test": "^1.12.6",
"terser-webpack-plugin": "^4.2.3",
"webpack": "^4.41.2",
"webpack-bundle-analyzer": "^3.7.0",
"webpack-cli": "^3.1.2",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "^3.4.1",
"webpack-node-externals": "^1.7.2",
"yarn-upgrade-all": "^0.5.0"
"webpack-node-externals": "^3.0.0"
},
"files": [
"dist"
],
"yarn-upgrade-all": {
"ignore": [
"babel-core"
]
},
"sideEffects": [
"**/*.css",
"**/*.scss"
@ -112,4 +100,4 @@
"pre-push": "yarn test"
}
}
}
}

View File

@ -1,3 +1,3 @@
module.exports = function(txt) {
module.exports = function (txt) {
return txt;
};

View File

@ -55,7 +55,7 @@ export const updateCurrentConfig = (siteCfg, _directives) => {
* @param conf - the base currentConfig to use as siteConfig
* @returns {*} - the siteConfig
*/
export const setSiteConfig = conf => {
export const setSiteConfig = (conf) => {
siteConfig = assignWithDepth({}, defaultConfig);
siteConfig = assignWithDepth(siteConfig, conf);
@ -67,11 +67,11 @@ export const setSiteConfig = conf => {
return siteConfig;
};
export const saveConfigFromInitilize = conf => {
export const saveConfigFromInitilize = (conf) => {
configFromInitialize = assignWithDepth({}, conf);
};
export const updateSiteConfig = conf => {
export const updateSiteConfig = (conf) => {
siteConfig = assignWithDepth(siteConfig, conf);
updateCurrentConfig(siteConfig, directives);
@ -101,7 +101,7 @@ export const getSiteConfig = () => {
* @param conf - the potential currentConfig
* @returns {*} - the currentConfig merged with the sanitized conf
*/
export const setConfig = conf => {
export const setConfig = (conf) => {
// sanitize(conf);
// Object.keys(conf).forEach(key => {
// const manipulator = manipulators[key];
@ -134,9 +134,9 @@ export const getConfig = () => {
*Note: modifies options in-place
* @param options - the potential setConfig parameter
*/
export const sanitize = options => {
export const sanitize = (options) => {
// Checking that options are not in the list of excluded options
Object.keys(siteConfig.secure).forEach(key => {
Object.keys(siteConfig.secure).forEach((key) => {
if (typeof options[siteConfig.secure[key]] !== 'undefined') {
// DO NOT attempt to print options[siteConfig.secure[key]] within `${}` as a malicious script
// can exploit the logger's attempt to stringify the value and execute arbitrary code
@ -149,14 +149,14 @@ export const sanitize = options => {
});
// Check that there no attempts of prototype pollution
Object.keys(options).forEach(key => {
Object.keys(options).forEach((key) => {
if (key.indexOf('__') === 0) {
delete options[key];
}
});
// Check that there no attempts of xss, there should be no tags at all in the directive
// blocking data urls as base64 urls can contain svgs with inline script tags
Object.keys(options).forEach(key => {
Object.keys(options).forEach((key) => {
if (typeof options[key] === 'string') {
if (
options[key].indexOf('<') > -1 ||
@ -172,7 +172,7 @@ export const sanitize = options => {
});
};
export const addDirective = directive => {
export const addDirective = (directive) => {
if (directive.fontFamily) {
if (!directive.themeVariables) {
directive.themeVariables = { fontFamily: directive.fontFamily };

View File

@ -10,12 +10,12 @@ import config from './defaultConfig';
// import themeForestVariables from './theme-forest';
// import themeNeutralVariables from './theme-neutral';
const handleThemeVariables = value => {
const handleThemeVariables = (value) => {
return theme[value] ? theme[value].getThemeVariables() : theme.default.getThemeVariables();
};
const manipulators = {
themeVariables: handleThemeVariables
themeVariables: handleThemeVariables,
};
// debugger;
@ -40,10 +40,10 @@ const currentConfig = assignWithDepth({}, defaultConfig);
* @param conf - the base currentConfig to use as siteConfig
* @returns {*} - the siteConfig
*/
export const setSiteConfig = conf => {
export const setSiteConfig = (conf) => {
console.log('setSiteConfig');
Object.keys(conf).forEach(key => {
Object.keys(conf).forEach((key) => {
const manipulator = manipulators[key];
conf[key] = manipulator ? manipulator(conf[key]) : conf[key];
});
@ -78,10 +78,10 @@ export const getSiteConfig = () => {
* @param conf - the potential currentConfig
* @returns {*} - the currentConfig merged with the sanitized conf
*/
export const setConfig = conf => {
export const setConfig = (conf) => {
console.log('setConfig');
sanitize(conf);
Object.keys(conf).forEach(key => {
Object.keys(conf).forEach((key) => {
const manipulator = manipulators[key];
conf[key] = manipulator ? manipulator(conf[key]) : conf[key];
});
@ -110,8 +110,8 @@ export const getConfig = () => {
*Note: modifies options in-place
* @param options - the potential setConfig parameter
*/
export const sanitize = options => {
Object.keys(siteConfig.secure).forEach(key => {
export const sanitize = (options) => {
Object.keys(siteConfig.secure).forEach((key) => {
if (typeof options[siteConfig.secure[key]] !== 'undefined') {
// DO NOT attempt to print options[siteConfig.secure[key]] within `${}` as a malicious script
// can exploit the logger's attempt to stringify the value and execute arbitrary code
@ -139,8 +139,8 @@ export const sanitize = options => {
*/
export const reset = (conf = getSiteConfig()) => {
console.warn('reset');
Object.keys(siteConfig).forEach(key => delete siteConfig[key]);
Object.keys(currentConfig).forEach(key => delete currentConfig[key]);
Object.keys(siteConfig).forEach((key) => delete siteConfig[key]);
Object.keys(currentConfig).forEach((key) => delete currentConfig[key]);
assignWithDepth(siteConfig, conf, { clobber: true });
assignWithDepth(currentConfig, conf, { clobber: true });
};
@ -152,6 +152,6 @@ const configApi = Object.freeze({
setConfig,
getConfig,
reset,
defaultConfig
defaultConfig,
});
export default configApi;

View File

@ -3,6 +3,7 @@ import { log } from '../logger';
import createLabel from './createLabel';
import { select } from 'd3';
import { getConfig } from '../config';
import { evaluate } from '../diagrams/common/common';
const rect = (parent, node) => {
log.trace('Creating subgraph rect for ', node.id, node);
@ -26,7 +27,7 @@ const rect = (parent, node) => {
// Get the size of the label
let bbox = text.getBBox();
if (getConfig().flowchart.htmlLabels) {
if (evaluate(getConfig().flowchart.htmlLabels)) {
const div = text.children[0];
const dv = select(text);
bbox = div.getBoundingClientRect();
@ -37,15 +38,22 @@ const rect = (parent, node) => {
const padding = 0 * node.padding;
const halfPadding = padding / 2;
const width = node.width <= bbox.width + padding ? bbox.width + padding : node.width;
if (node.width <= bbox.width + padding) {
node.diff = (bbox.width - node.width) / 2;
} else {
node.diff = -node.padding / 2;
}
log.trace('Data ', node, JSON.stringify(node));
// center the rect around its coordinate
rect
.attr('style', node.style)
.attr('rx', node.rx)
.attr('ry', node.ry)
.attr('x', node.x - node.width / 2 - halfPadding)
.attr('x', node.x - width / 2)
.attr('y', node.y - node.height / 2 - halfPadding)
.attr('width', node.width + padding)
.attr('width', width)
.attr('height', node.height + padding);
// Center the label
@ -62,7 +70,7 @@ const rect = (parent, node) => {
node.width = rectBox.width;
node.height = rectBox.height;
node.intersect = function(point) {
node.intersect = function (point) {
return intersectRect(node, point);
};
@ -74,10 +82,7 @@ const rect = (parent, node) => {
*/
const noteGroup = (parent, node) => {
// Add outer g element
const shapeSvg = parent
.insert('g')
.attr('class', 'note-cluster')
.attr('id', node.id);
const shapeSvg = parent.insert('g').attr('class', 'note-cluster').attr('id', node.id);
// add the rect
const rect = shapeSvg.insert('rect', ':first-child');
@ -99,7 +104,7 @@ const noteGroup = (parent, node) => {
node.width = rectBox.width;
node.height = rectBox.height;
node.intersect = function(point) {
node.intersect = function (point) {
return intersectRect(node, point);
};
@ -107,10 +112,7 @@ const noteGroup = (parent, node) => {
};
const roundedWithTitle = (parent, node) => {
// Add outer g element
const shapeSvg = parent
.insert('g')
.attr('class', node.classes)
.attr('id', node.id);
const shapeSvg = parent.insert('g').attr('class', node.classes).attr('id', node.id);
// add the rect
const rect = shapeSvg.insert('rect', ':first-child');
@ -125,7 +127,7 @@ const roundedWithTitle = (parent, node) => {
// Get the size of the label
let bbox = text.getBBox();
if (getConfig().flowchart.htmlLabels) {
if (evaluate(getConfig().flowchart.htmlLabels)) {
const div = text.children[0];
const dv = select(text);
bbox = div.getBoundingClientRect();
@ -136,18 +138,25 @@ const roundedWithTitle = (parent, node) => {
const padding = 0 * node.padding;
const halfPadding = padding / 2;
const width = node.width <= bbox.width + node.padding ? bbox.width + node.padding : node.width;
if (node.width <= bbox.width + node.padding) {
node.diff = (bbox.width + node.padding * 0 - node.width) / 2;
} else {
node.diff = -node.padding / 2;
}
// center the rect around its coordinate
rect
.attr('class', 'outer')
.attr('x', node.x - node.width / 2 - halfPadding)
.attr('x', node.x - width / 2 - halfPadding)
.attr('y', node.y - node.height / 2 - halfPadding)
.attr('width', node.width + padding)
.attr('width', width + padding)
.attr('height', node.height + padding);
innerRect
.attr('class', 'inner')
.attr('x', node.x - node.width / 2 - halfPadding)
.attr('x', node.x - width / 2 - halfPadding)
.attr('y', node.y - node.height / 2 - halfPadding + bbox.height - 1)
.attr('width', node.width + padding)
.attr('width', width + padding)
.attr('height', node.height + padding - bbox.height - 3);
// Center the label
@ -156,15 +165,17 @@ const roundedWithTitle = (parent, node) => {
'translate(' +
(node.x - bbox.width / 2) +
', ' +
(node.y - node.height / 2 - node.padding / 3 + (getConfig().flowchart.htmlLabels ? 5 : 3)) +
(node.y -
node.height / 2 -
node.padding / 3 +
(evaluate(getConfig().flowchart.htmlLabels) ? 5 : 3)) +
')'
);
const rectBox = rect.node().getBBox();
node.width = rectBox.width;
node.height = rectBox.height;
node.intersect = function(point) {
node.intersect = function (point) {
return intersectRect(node, point);
};
@ -173,10 +184,7 @@ const roundedWithTitle = (parent, node) => {
const divider = (parent, node) => {
// Add outer g element
const shapeSvg = parent
.insert('g')
.attr('class', node.classes)
.attr('id', node.id);
const shapeSvg = parent.insert('g').attr('class', node.classes).attr('id', node.id);
// add the rect
const rect = shapeSvg.insert('rect', ':first-child');
@ -195,8 +203,8 @@ const divider = (parent, node) => {
const rectBox = rect.node().getBBox();
node.width = rectBox.width;
node.height = rectBox.height;
node.intersect = function(point) {
node.diff = -node.padding / 2;
node.intersect = function (point) {
return intersectRect(node, point);
};
@ -224,8 +232,8 @@ export const clear = () => {
clusterElems = {};
};
export const positionCluster = node => {
log.info('Position cluster');
export const positionCluster = (node) => {
log.info('Position cluster (' + node.id + ', ' + node.x + ', ' + node.y + ')');
const el = clusterElems[node.id];
el.attr('transform', 'translate(' + node.x + ', ' + node.y + ')');

View File

@ -1,7 +1,8 @@
import { select } from 'd3';
import { log } from '../logger'; // eslint-disable-line
import { evaluate } from '../diagrams/common/common';
// let vertexNode;
// if (getConfig().flowchart.htmlLabels) {
// if (evaluate(getConfig().flowchart.htmlLabels)) {
// // TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
// const node = {
// label: vertexText.replace(/fa[lrsb]?:fa-[\w-]+/g, s => `<i class='${s.replace(':', ' ')}'></i>`)
@ -85,7 +86,8 @@ function addHtmlLabel(node) {
const createLabel = (_vertexText, style, isTitle, isNode) => {
let vertexText = _vertexText || '';
if (getConfig().flowchart.htmlLabels) {
if (typeof vertexText === 'object') vertexText = vertexText[0];
if (evaluate(getConfig().flowchart.htmlLabels)) {
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
vertexText = vertexText.replace(/\\n|\n/g, '<br />');
log.info('vertexText' + vertexText);
@ -93,9 +95,9 @@ const createLabel = (_vertexText, style, isTitle, isNode) => {
isNode,
label: vertexText.replace(
/fa[lrsb]?:fa-[\w-]+/g,
s => `<i class='${s.replace(':', ' ')}'></i>`
(s) => `<i class='${s.replace(':', ' ')}'></i>`
),
labelStyle: style.replace('fill:', 'color:')
labelStyle: style.replace('fill:', 'color:'),
};
let vertexNode = addHtmlLabel(node);
// vertexNode.parentNode.removeChild(vertexNode);

View File

@ -1,9 +1,10 @@
import { log } from '../logger'; // eslint-disable-line
import createLabel from './createLabel';
// import { line, curveBasis, curveLinear, select } from 'd3';
import { line, curveBasis, select } from 'd3';
import { getConfig } from '../config';
import utils from '../utils';
// import { calcLabelPosition } from '../utils';
import { evaluate } from '../diagrams/common/common';
let edgeLabels = {};
let terminalLabels = {};
@ -26,7 +27,7 @@ export const insertEdgeLabel = (elem, edge) => {
// Center the label
let bbox = labelElement.getBBox();
if (getConfig().flowchart.htmlLabels) {
if (evaluate(getConfig().flowchart.htmlLabels)) {
const div = labelElement.children[0];
const dv = select(labelElement);
bbox = div.getBoundingClientRect();
@ -42,25 +43,27 @@ export const insertEdgeLabel = (elem, edge) => {
edge.width = bbox.width;
edge.height = bbox.height;
let fo;
if (edge.startLabelLeft) {
// Create the actual text element
const startLabelElement = createLabel(edge.startLabelLeft, edge.labelStyle);
const startEdgeLabelLeft = elem.insert('g').attr('class', 'edgeTerminals');
const inner = startEdgeLabelLeft.insert('g').attr('class', 'inner');
inner.node().appendChild(startLabelElement);
fo = inner.node().appendChild(startLabelElement);
const slBox = startLabelElement.getBBox();
inner.attr('transform', 'translate(' + -slBox.width / 2 + ', ' + -slBox.height / 2 + ')');
if (!terminalLabels[edge.id]) {
terminalLabels[edge.id] = {};
}
terminalLabels[edge.id].startLeft = startEdgeLabelLeft;
setTerminalWidth(fo, edge.startLabelLeft);
}
if (edge.startLabelRight) {
// Create the actual text element
const startLabelElement = createLabel(edge.startLabelRight, edge.labelStyle);
const startEdgeLabelRight = elem.insert('g').attr('class', 'edgeTerminals');
const inner = startEdgeLabelRight.insert('g').attr('class', 'inner');
startEdgeLabelRight.node().appendChild(startLabelElement);
fo = startEdgeLabelRight.node().appendChild(startLabelElement);
inner.node().appendChild(startLabelElement);
const slBox = startLabelElement.getBBox();
inner.attr('transform', 'translate(' + -slBox.width / 2 + ', ' + -slBox.height / 2 + ')');
@ -69,21 +72,24 @@ export const insertEdgeLabel = (elem, edge) => {
terminalLabels[edge.id] = {};
}
terminalLabels[edge.id].startRight = startEdgeLabelRight;
setTerminalWidth(fo, edge.startLabelRight);
}
if (edge.endLabelLeft) {
// Create the actual text element
const endLabelElement = createLabel(edge.endLabelLeft, edge.labelStyle);
const endEdgeLabelLeft = elem.insert('g').attr('class', 'edgeTerminals');
const inner = endEdgeLabelLeft.insert('g').attr('class', 'inner');
inner.node().appendChild(endLabelElement);
fo = inner.node().appendChild(endLabelElement);
const slBox = endLabelElement.getBBox();
inner.attr('transform', 'translate(' + -slBox.width / 2 + ', ' + -slBox.height / 2 + ')');
endEdgeLabelLeft.node().appendChild(endLabelElement);
if (!terminalLabels[edge.id]) {
terminalLabels[edge.id] = {};
}
terminalLabels[edge.id].endLeft = endEdgeLabelLeft;
setTerminalWidth(fo, edge.endLabelLeft);
}
if (edge.endLabelRight) {
// Create the actual text element
@ -91,7 +97,7 @@ export const insertEdgeLabel = (elem, edge) => {
const endEdgeLabelRight = elem.insert('g').attr('class', 'edgeTerminals');
const inner = endEdgeLabelRight.insert('g').attr('class', 'inner');
inner.node().appendChild(endLabelElement);
fo = inner.node().appendChild(endLabelElement);
const slBox = endLabelElement.getBBox();
inner.attr('transform', 'translate(' + -slBox.width / 2 + ', ' + -slBox.height / 2 + ')');
@ -100,11 +106,19 @@ export const insertEdgeLabel = (elem, edge) => {
terminalLabels[edge.id] = {};
}
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) => {
log.info('Moving label', 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;
if (edge.label) {
const el = edgeLabels[edge.id];
@ -113,7 +127,7 @@ export const positionEdgeLabel = (edge, paths) => {
if (path) {
// // debugger;
const pos = utils.calcLabelPosition(path);
log.info('Moving label from (', x, ',', y, ') to (', pos.x, ',', pos.y, ')');
log.info('Moving label from (', x, ',', y, ') to (', pos.x, ',', pos.y, ') abc78');
// x = pos.x;
// y = pos.y;
}
@ -127,7 +141,7 @@ export const positionEdgeLabel = (edge, paths) => {
let y = edge.y;
if (path) {
// debugger;
const pos = utils.calcTerminalLabelPosition(0, 'start_left', path);
const pos = utils.calcTerminalLabelPosition(edge.arrowTypeStart ? 10 : 0, 'start_left', path);
x = pos.x;
y = pos.y;
}
@ -139,7 +153,11 @@ export const positionEdgeLabel = (edge, paths) => {
let y = edge.y;
if (path) {
// debugger;
const pos = utils.calcTerminalLabelPosition(0, 'start_right', path);
const pos = utils.calcTerminalLabelPosition(
edge.arrowTypeStart ? 10 : 0,
'start_right',
path
);
x = pos.x;
y = pos.y;
}
@ -151,7 +169,7 @@ export const positionEdgeLabel = (edge, paths) => {
let y = edge.y;
if (path) {
// debugger;
const pos = utils.calcTerminalLabelPosition(0, 'end_left', path);
const pos = utils.calcTerminalLabelPosition(edge.arrowTypeEnd ? 10 : 0, 'end_left', path);
x = pos.x;
y = pos.y;
}
@ -163,7 +181,7 @@ export const positionEdgeLabel = (edge, paths) => {
let y = edge.y;
if (path) {
// debugger;
const pos = utils.calcTerminalLabelPosition(0, 'end_right', path);
const pos = utils.calcTerminalLabelPosition(edge.arrowTypeEnd ? 10 : 0, 'end_right', path);
x = pos.x;
y = pos.y;
}
@ -199,31 +217,35 @@ const outsideNode = (node, point) => {
};
export const intersection = (node, outsidePoint, insidePoint) => {
log.warn('intersection calc o:', outsidePoint, ' i:', insidePoint, node);
log.warn(`intersection calc abc89:
outsidePoint: ${JSON.stringify(outsidePoint)}
insidePoint : ${JSON.stringify(insidePoint)}
node : x:${node.x} y:${node.y} w:${node.width} h:${node.height}`);
const x = node.x;
const y = node.y;
const dx = Math.abs(x - insidePoint.x);
// const dy = Math.abs(y - insidePoint.y);
const w = node.width / 2;
let r = insidePoint.x < outsidePoint.x ? w - dx : w + dx;
const h = node.height / 2;
const edges = {
x1: x - w,
x2: x + w,
y1: y - h,
y2: y + h
};
// 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
) {
log.warn('calc equals on edge');
return outsidePoint;
}
// if (
// outsidePoint.x === edges.x1 ||
// outsidePoint.x === edges.x2 ||
// outsidePoint.y === edges.y1 ||
// outsidePoint.y === edges.y2
// ) {
// log.warn('abc89 calc equals on edge', outsidePoint, edges);
// return outsidePoint;
// }
const Q = Math.abs(outsidePoint.y - insidePoint.y);
const R = Math.abs(outsidePoint.x - insidePoint.x);
@ -234,43 +256,110 @@ export const intersection = (node, outsidePoint, insidePoint) => {
let q = insidePoint.y < outsidePoint.y ? outsidePoint.y - h - y : y - h - outsidePoint.y;
r = (R * q) / Q;
const res = {
x: insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : insidePoint.x - r,
y: insidePoint.y < outsidePoint.y ? insidePoint.y + Q - q : insidePoint.y - q
x: insidePoint.x < outsidePoint.x ? insidePoint.x + r : insidePoint.x - R + r,
y: insidePoint.y < outsidePoint.y ? insidePoint.y + Q - q : insidePoint.y - Q + q,
};
log.warn(`topp/bott calc, Q ${Q}, q ${q}, R ${R}, r ${r}`, res);
if (r === 0) {
res.x = outsidePoint.x;
res.y = outsidePoint.y;
}
if (R === 0) {
res.x = outsidePoint.x;
}
if (Q === 0) {
res.y = outsidePoint.y;
}
log.warn(`abc89 topp/bott calc, Q ${Q}, q ${q}, R ${R}, r ${r}`, res);
return res;
} else {
// 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);
log.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
});
let q = (Q * r) / R;
// OK let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : insidePoint.x + dx - w;
// OK let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : outsidePoint.x + r;
let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : insidePoint.x - R + r;
// let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : outsidePoint.x + r;
let _y = insidePoint.y < outsidePoint.y ? insidePoint.y + q : insidePoint.y - q;
log.warn(`sides calc abc89, Q ${Q}, q ${q}, R ${R}, r ${r}`, { _x, _y });
if (r === 0) {
_x = outsidePoint.x;
_y = outsidePoint.y;
}
if (R === 0) {
_x = outsidePoint.x;
}
if (Q === 0) {
_y = outsidePoint.y;
}
return {
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: _x, y: _y };
}
};
/**
* This function will page a path and node where the last point(s) in the path is inside the node
* and return an update path ending by the border of the node.
* @param {*} points
* @param {*} boundryNode
* @returns
*/
const cutPathAtIntersect = (_points, boundryNode) => {
log.warn('abc88 cutPathAtIntersect', _points, boundryNode);
let points = [];
let lastPointOutside = _points[0];
let isInside = false;
_points.forEach((point) => {
// const node = clusterDb[edge.toCluster].node;
log.info('abc88 checking point', point, boundryNode);
// check if point is inside the boundry rect
if (!outsideNode(boundryNode, point) && !isInside) {
// First point inside the rect found
// Calc the intersection coord between the point anf the last opint ouside the rect
const inter = intersection(boundryNode, lastPointOutside, point);
log.warn('abc88 inside', point, lastPointOutside, inter);
log.warn('abc88 intersection', inter);
// // Check case where the intersection is the same as the last 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 {
log.warn('abc88 no intersect', inter, points);
}
// points.push(inter);
isInside = true;
} else {
// Outside
log.warn('abc88 outside', point, lastPointOutside);
lastPointOutside = point;
// points.push(point);
if (!isInside) points.push(point);
}
});
log.warn('abc88 returning points', points);
return points;
};
//(edgePaths, e, edge, clusterDb, diagramtype, graph)
export const insertEdge = function(elem, 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);
log.info('abc88 InsertEdge: ', edge);
if (head.intersect && tail.intersect) {
points = points.slice(1, edge.points.length - 1);
points.unshift(tail.intersect(points[0]));
@ -283,71 +372,89 @@ export const insertEdge = function(elem, e, edge, clusterDb, diagramType, graph)
points.push(head.intersect(points[points.length - 1]));
}
if (edge.toCluster) {
log.trace('edge', edge);
log.trace('to cluster', clusterDb[edge.toCluster]);
points = [];
let lastPointOutside;
let isInside = false;
edge.points.forEach(point => {
const node = clusterDb[edge.toCluster].node;
log.info('to cluster abc88', clusterDb[edge.toCluster]);
points = cutPathAtIntersect(edge.points, clusterDb[edge.toCluster].node);
// log.trace('edge', edge);
// points = [];
// let lastPointOutside; // = edge.points[0];
// let isInside = false;
// edge.points.forEach(point => {
// const node = clusterDb[edge.toCluster].node;
// log.warn('checking from', edge.fromCluster, point, node);
if (!outsideNode(node, point) && !isInside) {
log.trace('inside', edge.toCluster, point, lastPointOutside);
// if (!outsideNode(node, point) && !isInside) {
// log.trace('inside', edge.toCluster, point, lastPointOutside);
// First point inside the rect
const inter = intersection(node, lastPointOutside, point);
// // First point inside the rect
// 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 {
log.warn('no intersect', inter, points);
}
isInside = true;
} else {
if (!isInside) points.push(point);
}
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 {
// log.warn('no intersect', inter, points);
// }
// isInside = true;
// } else {
// // outtside
// lastPointOutside = point;
// if (!isInside) points.push(point);
// }
// });
pointsHasChanged = true;
}
if (edge.fromCluster) {
log.trace('edge', edge);
log.warn('from cluster', clusterDb[edge.fromCluster]);
const updatedPoints = [];
let lastPointOutside;
let isInside = false;
for (let i = points.length - 1; i >= 0; i--) {
const point = points[i];
const node = clusterDb[edge.fromCluster].node;
log.info('from cluster abc88', clusterDb[edge.fromCluster]);
points = cutPathAtIntersect(points.reverse(), clusterDb[edge.fromCluster].node).reverse();
// log.warn('edge', edge);
// log.warn('from cluster', clusterDb[edge.fromCluster], points);
// const updatedPoints = [];
// let lastPointOutside = edge.points[edge.points.length - 1];
// let isInside = false;
// for (let i = points.length - 1; i >= 0; i--) {
// const point = points[i];
// const node = clusterDb[edge.fromCluster].node;
// log.warn('checking to', edge.fromCluster, point, node);
if (!outsideNode(node, point) && !isInside) {
log.warn('inside', edge.fromCluster, point, node);
// if (!outsideNode(node, point) && !isInside) {
// log.warn('inside', edge.fromCluster, point, node);
// First point inside the rect
const insterection = intersection(node, lastPointOutside, point);
// log.trace('intersect', intersection(node, lastPointOutside, point));
updatedPoints.unshift(insterection);
// points.push(insterection);
isInside = true;
} else {
// at the outside
log.trace('Outside point', point);
if (!isInside) updatedPoints.unshift(point);
}
lastPointOutside = point;
}
points = updatedPoints;
// // First point inside the rect
// const inter = intersection(node, lastPointOutside, point);
// log.warn('intersect', 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)) {
// updatedPoints.unshift(inter);
// log.warn('Adding point -updated = ', updatedPoints);
// } else {
// log.warn('no intersect', inter, points);
// }
// // points.push(insterection);
// isInside = true;
// } else {
// // at the outside
// // if (!isInside) updatedPoints.unshift(point);
// updatedPoints.unshift(point);
// log.warn('Outside point', point, updatedPoints);
// }
// lastPointOutside = point;
// }
// points = updatedPoints;
// points = edge.points;
pointsHasChanged = true;
}
// The data for our line
const lineData = points.filter(p => !Number.isNaN(p.y));
const lineData = points.filter((p) => !Number.isNaN(p.y));
// This is the accessor function we talked about above
let curve;
@ -359,11 +466,12 @@ export const insertEdge = function(elem, e, edge, clusterDb, diagramType, graph)
} else {
curve = curveBasis;
}
// curve = curveLinear;
const lineFunction = line()
.x(function(d) {
.x(function (d) {
return d.x;
})
.y(function(d) {
.y(function (d) {
return d.y;
})
.curve(curve);

View File

@ -32,33 +32,33 @@ describe('Graphlib decorations', () => {
});
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 o = {x: 157, y: 39};
const i = {x: 104, y: 105};
const node2 = {
width: 211.96875,
x: 113.984375,
y: 164.25,
height: 176.5
width: 212,
x: 114,
y: 164,
height: 176
}
const int = intersection(node2, o, i);
expect(int.x).toBeCloseTo(127.39979619565217)
// expect(int.y).toBeCloseTo(76)
expect(int.y).toBeCloseTo(67.833)
expect(int.x).toBeCloseTo(133.71)
expect(int.y).toBeCloseTo(76)
// expect(int.y).toBeCloseTo(67.833)
});
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 o = {x: 144, y: 38};
const i = {x: 198, y: 105};
const node2 = {
width: 211.96875,
x: 113.984375,
y: 164.25,
height: 176.5
width: 212,
x: 114,
y: 164,
height: 176
}
const int = intersection(node2, o, i);
expect(int.x).toBeCloseTo(167.9232336956522)
// expect(int.y).toBeCloseTo(76)
expect(int.y).toBeCloseTo(67.833)
expect(int.x).toBeCloseTo(174.626 )
expect(int.y).toBeCloseTo(76)
// expect(int.y).toBeCloseTo(67.833)
});
});

View File

@ -7,7 +7,7 @@ import {
clusterDb,
adjustClustersAndEdges,
findNonClusterChild,
sortNodesByHierarchy
sortNodesByHierarchy,
} from './mermaid-graphlib';
import { insertNode, positionNode, clear as clearNodes, setNodeElem } from './nodes';
import { insertCluster, clear as clearClusters } from './clusters';
@ -17,7 +17,7 @@ import { log } from '../logger';
const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
log.info('Graph in recursive render: XXX', graphlib.json.write(graph), parentCluster);
const dir = graph.graph().rankdir;
log.warn('Dir in recursive render - dir:', dir);
log.trace('Dir in recursive render - dir:', dir);
const elem = _elem.insert('g').attr('class', 'root'); // eslint-disable-line
if (!graph.nodes()) {
@ -26,7 +26,7 @@ const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
log.info('Recursive render XXX', graph.nodes());
}
if (graph.edges().length > 0) {
log.info('Recursive edges', graph.edge(graph.edges()[0]));
log.trace('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');
@ -35,7 +35,7 @@ const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
// Insert nodes, this will insert them into the dom and each node will get a size. The size is updated
// to the abstract node and is later used by dagre for the layout
graph.nodes().forEach(function(v) {
graph.nodes().forEach(function (v) {
const node = graph.node(v);
if (typeof parentCluster !== 'undefined') {
const data = JSON.parse(JSON.stringify(parentCluster.clusterData));
@ -43,19 +43,22 @@ const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
log.info('Setting data for cluster XXX (', v, ') ', data, parentCluster);
graph.setNode(parentCluster.id, data);
if (!graph.parent(v)) {
log.warn('Setting parent', v, parentCluster.id);
log.trace('Setting parent', v, parentCluster.id);
graph.setParent(v, parentCluster.id, data);
}
}
log.info('(Insert) Node XXX' + v + ': ' + JSON.stringify(graph.node(v)));
if (node && node.clusterNode) {
// const children = graph.children(v);
log.info('Cluster identified', v, node, graph.node(v));
const newEl = recursiveRender(nodes, node.graph, diagramtype, graph.node(v));
log.info('Cluster identified', v, node.width, graph.node(v));
const o = recursiveRender(nodes, node.graph, diagramtype, graph.node(v));
const newEl = o.elem;
updateNodeBounds(node, newEl);
node.diff = o.diff || 0;
log.info('Node bounds (abc123)', v, node, node.width, node.x, node.y);
setNodeElem(newEl, node);
log.warn('Recursive render complete', newEl, node);
log.warn('Recursive render complete ', newEl, node);
} else {
if (graph.children(v).length > 0) {
// This is a cluster but not to be rendered recusively
@ -75,7 +78,7 @@ const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
// Also figure out which edges point to/from clusters and adjust them accordingly
// Edges from/to clusters really points to the first child in the cluster.
// TODO: pick optimal child in the cluster to us as link anchor
graph.edges().forEach(function(e) {
graph.edges().forEach(function (e) {
const edge = graph.edge(e.v, e.w, e.name);
log.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(e));
log.info('Edge ' + e.v + ' -> ' + e.w + ': ', e, ' ', JSON.stringify(graph.edge(e)));
@ -85,7 +88,7 @@ const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
insertEdgeLabel(edgeLabels, edge);
});
graph.edges().forEach(function(e) {
graph.edges().forEach(function (e) {
log.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(e));
});
log.info('#############################################');
@ -95,7 +98,8 @@ const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
dagre.layout(graph);
log.info('Graph after layout:', graphlib.json.write(graph));
// Move the nodes to the correct place
sortNodesByHierarchy(graph).forEach(function(v) {
let diff = 0;
sortNodesByHierarchy(graph).forEach(function (v) {
const node = graph.node(v);
log.info('Position ' + v + ': ' + JSON.stringify(graph.node(v)));
log.info(
@ -124,7 +128,7 @@ const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
});
// Move the edge labels to the correct place after layout
graph.edges().forEach(function(e) {
graph.edges().forEach(function (e) {
const edge = graph.edge(e);
log.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(edge), edge);
@ -132,7 +136,14 @@ const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
positionEdgeLabel(edge, paths);
});
return elem;
graph.nodes().forEach(function (v) {
const n = graph.node(v);
log.info(v, n.type, n.diff);
if (n.type === 'group') {
diff = n.diff;
}
});
return { elem, diff };
};
export const render = (elem, graph, markers, diagramtype, id) => {

View File

@ -3,5 +3,5 @@ module.exports = {
circle: require('./intersect-circle'),
ellipse: require('./intersect-ellipse'),
polygon: require('./intersect-polygon'),
rect: require('./intersect-rect')
rect: require('./intersect-rect'),
};

View File

@ -13,5 +13,5 @@ export default {
circle,
ellipse,
polygon,
rect
rect,
};

View File

@ -17,7 +17,7 @@ function intersectPolygon(node, polyPoints, point) {
var minX = Number.POSITIVE_INFINITY;
var minY = Number.POSITIVE_INFINITY;
if (typeof polyPoints.forEach === 'function') {
polyPoints.forEach(function(entry) {
polyPoints.forEach(function (entry) {
minX = Math.min(minX, entry.x);
minY = Math.min(minY, entry.y);
});
@ -50,7 +50,7 @@ function intersectPolygon(node, polyPoints, point) {
if (intersections.length > 1) {
// More intersections, find the one nearest to edge end point
intersections.sort(function(p, q) {
intersections.sort(function (p, q) {
var pdx = p.x - point.x;
var pdy = p.y - point.y;
var distp = Math.sqrt(pdx * pdx + pdy * pdy);

View File

@ -6,7 +6,7 @@ import { log } from '../logger';
// Only add the number of markers that the diagram needs
const insertMarkers = (elem, markerArray, type, id) => {
markerArray.forEach(markerName => {
markerArray.forEach((markerName) => {
markers[markerName](elem, type, id);
});
};
@ -255,6 +255,6 @@ const markers = {
point,
circle,
cross,
barb
barb,
};
export default insertMarkers;

View File

@ -17,7 +17,7 @@ export const clear = () => {
const isDecendant = (id, ancenstorId) => {
// if (id === ancenstorId) return true;
log.debug(
log.trace(
'In isDecendant',
ancenstorId,
' ',
@ -70,7 +70,7 @@ const copy = (clusterId, graph, newGraph, rootId) => {
log.warn('Copying (nodes) clusterId', clusterId, 'nodes', nodes);
nodes.forEach(node => {
nodes.forEach((node) => {
if (graph.children(node).length > 0) {
copy(node, graph, newGraph, rootId);
} else {
@ -98,7 +98,7 @@ const copy = (clusterId, graph, newGraph, rootId) => {
}
const edges = graph.edges(node);
log.debug('Copying Edges', edges);
edges.forEach(edge => {
edges.forEach((edge) => {
log.info('Edge', edge);
const data = graph.edge(edge.v, edge.w, edge.name);
log.info('Edge data', data, rootId);
@ -147,7 +147,7 @@ export const extractDecendants = (id, graph) => {
* edges between nodes also ia correct. When not correct the function logs the discrepancies.
* @param {graphlib graph} g
*/
export const validate = graph => {
export const validate = (graph) => {
const edges = graph.edges();
log.trace('Edges: ', edges);
for (let i = 0; i < edges.length; i++) {
@ -187,7 +187,7 @@ export const findNonClusterChild = (id, graph) => {
}
};
const getAnchorId = id => {
const getAnchorId = (id) => {
if (!clusterDb[id]) {
return id;
}
@ -212,7 +212,7 @@ export const adjustClustersAndEdges = (graph, depth) => {
}
// Go through the nodes and for each cluster found, save a replacment node, this can be used when
// faking a link to a cluster
graph.nodes().forEach(function(id) {
graph.nodes().forEach(function (id) {
const children = graph.children(id);
if (children.length > 0) {
log.warn(
@ -227,12 +227,12 @@ export const adjustClustersAndEdges = (graph, depth) => {
});
// Check incoming and outgoing edges for each cluster
graph.nodes().forEach(function(id) {
graph.nodes().forEach(function (id) {
const children = graph.children(id);
const edges = graph.edges();
if (children.length > 0) {
log.debug('Cluster identified', id, decendants);
edges.forEach(edge => {
edges.forEach((edge) => {
// log.debug('Edge, decendants: ', edge, decendants[id]);
// Check if any edge leaves the cluster (not the actual cluster, thats a link from the box)
@ -258,7 +258,7 @@ export const adjustClustersAndEdges = (graph, depth) => {
// For clusters with incoming and/or outgoing edges translate those edges to a real node
// in the cluster inorder to fake the edge
graph.edges().forEach(function(e) {
graph.edges().forEach(function (e) {
const edge = graph.edge(e);
log.warn('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(e));
log.warn('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(graph.edge(e)));
@ -358,20 +358,26 @@ export const extractor = (graph, depth) => {
);
const graphSettings = graph.graph();
let dir = graphSettings.rankdir === 'TB' ? 'LR' : 'TB';
if (clusterDb[node]) {
if (clusterDb[node].clusterData && clusterDb[node].clusterData.dir) {
dir = clusterDb[node].clusterData.dir;
log.warn('Fixing dir', clusterDb[node].clusterData.dir, dir);
}
}
const clusterGraph = new graphlib.Graph({
multigraph: true,
compound: true
compound: true,
})
.setGraph({
rankdir: graphSettings.rankdir === 'TB' ? 'LR' : 'TB',
// Todo: set proper spacing
rankdir: dir, // Todo: set proper spacing
nodesep: 50,
ranksep: 50,
marginx: 8,
marginy: 8
marginy: 8,
})
.setDefaultEdgeLabel(function() {
.setDefaultEdgeLabel(function () {
return {};
});
@ -382,7 +388,7 @@ export const extractor = (graph, depth) => {
id: node,
clusterData: clusterDb[node].clusterData,
labelText: clusterDb[node].labelText,
graph: clusterGraph
graph: clusterGraph,
});
log.warn('New graph after copy node: (', node, ')', graphlib.json.write(clusterGraph));
log.debug('Old graph after copy', graphlib.json.write(graph));
@ -418,7 +424,7 @@ export const extractor = (graph, depth) => {
const sorter = (graph, nodes) => {
if (nodes.length === 0) return [];
let result = Object.assign(nodes);
nodes.forEach(node => {
nodes.forEach((node) => {
const children = graph.children(node);
const sorted = sorter(graph, children);
result = result.concat(sorted);
@ -427,4 +433,4 @@ const sorter = (graph, nodes) => {
return result;
};
export const sortNodesByHierarchy = graph => sorter(graph, graph.children());
export const sortNodesByHierarchy = (graph) => sorter(graph, graph.children());

View File

@ -6,6 +6,7 @@ import intersect from './intersect/index.js';
import createLabel from './createLabel';
import note from './shapes/note';
import { parseMember } from '../diagrams/class/svgDraw';
import { evaluate } from '../diagrams/common/common';
const question = (parent, node) => {
const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
@ -17,7 +18,7 @@ const question = (parent, node) => {
{ x: s / 2, y: 0 },
{ x: s, y: -s / 2 },
{ x: s / 2, y: -s },
{ x: 0, y: -s / 2 }
{ x: 0, y: -s / 2 },
];
log.info('Question main (Circle)');
@ -26,7 +27,7 @@ const question = (parent, node) => {
questionElem.attr('style', node.style);
updateNodeBounds(node, questionElem);
node.intersect = function(point) {
node.intersect = function (point) {
log.warn('Intersect called');
return intersect.polygon(node, points, point);
};
@ -34,6 +35,40 @@ const question = (parent, node) => {
return shapeSvg;
};
const choice = (parent, node) => {
const shapeSvg = parent
.insert('g')
.attr('class', 'node default')
.attr('id', node.domId || node.id);
const s = 28;
const points = [
{ x: 0, y: s / 2 },
{ x: s / 2, y: 0 },
{ x: 0, y: -s / 2 },
{ x: -s / 2, y: 0 },
];
const choice = shapeSvg.insert('polygon', ':first-child').attr(
'points',
points
.map(function (d) {
return d.x + ',' + d.y;
})
.join(' ')
);
// center the circle around its coordinate
choice.attr('class', 'state-start').attr('r', 7).attr('width', 28).attr('height', 28);
node.width = 28;
node.height = 28;
node.intersect = function (point) {
return intersect.circle(node, 14, point);
};
return shapeSvg;
};
const hexagon = (parent, node) => {
const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
@ -47,14 +82,14 @@ const hexagon = (parent, node) => {
{ x: w, y: -h / 2 },
{ x: w - m, y: -h },
{ x: m, y: -h },
{ x: 0, y: -h / 2 }
{ x: 0, y: -h / 2 },
];
const hex = insertPolygonShape(shapeSvg, w, h, points);
hex.attr('style', node.style);
updateNodeBounds(node, hex);
node.intersect = function(point) {
node.intersect = function (point) {
return intersect.polygon(node, points, point);
};
@ -71,7 +106,7 @@ const rect_left_inv_arrow = (parent, node) => {
{ x: w, y: 0 },
{ x: w, y: -h },
{ x: -h / 2, y: -h },
{ x: 0, y: -h / 2 }
{ x: 0, y: -h / 2 },
];
const el = insertPolygonShape(shapeSvg, w, h, points);
@ -80,7 +115,7 @@ const rect_left_inv_arrow = (parent, node) => {
node.width = w + h;
node.height = h;
node.intersect = function(point) {
node.intersect = function (point) {
return intersect.polygon(node, points, point);
};
@ -96,14 +131,14 @@ const lean_right = (parent, node) => {
{ x: (-2 * h) / 6, y: 0 },
{ x: w - h / 6, y: 0 },
{ x: w + (2 * h) / 6, y: -h },
{ x: h / 6, y: -h }
{ x: h / 6, y: -h },
];
const el = insertPolygonShape(shapeSvg, w, h, points);
el.attr('style', node.style);
updateNodeBounds(node, el);
node.intersect = function(point) {
node.intersect = function (point) {
return intersect.polygon(node, points, point);
};
@ -119,14 +154,14 @@ const lean_left = (parent, node) => {
{ x: (2 * h) / 6, y: 0 },
{ x: w + h / 6, y: 0 },
{ x: w - (2 * h) / 6, y: -h },
{ x: -h / 6, y: -h }
{ x: -h / 6, y: -h },
];
const el = insertPolygonShape(shapeSvg, w, h, points);
el.attr('style', node.style);
updateNodeBounds(node, el);
node.intersect = function(point) {
node.intersect = function (point) {
return intersect.polygon(node, points, point);
};
@ -142,14 +177,14 @@ const trapezoid = (parent, node) => {
{ x: (-2 * h) / 6, y: 0 },
{ x: w + (2 * h) / 6, y: 0 },
{ x: w - h / 6, y: -h },
{ x: h / 6, y: -h }
{ x: h / 6, y: -h },
];
const el = insertPolygonShape(shapeSvg, w, h, points);
el.attr('style', node.style);
updateNodeBounds(node, el);
node.intersect = function(point) {
node.intersect = function (point) {
return intersect.polygon(node, points, point);
};
@ -165,14 +200,14 @@ const inv_trapezoid = (parent, node) => {
{ x: h / 6, y: 0 },
{ x: w - h / 6, y: 0 },
{ x: w + (2 * h) / 6, y: -h },
{ x: (-2 * h) / 6, y: -h }
{ x: (-2 * h) / 6, y: -h },
];
const el = insertPolygonShape(shapeSvg, w, h, points);
el.attr('style', node.style);
updateNodeBounds(node, el);
node.intersect = function(point) {
node.intersect = function (point) {
return intersect.polygon(node, points, point);
};
@ -189,14 +224,14 @@ const rect_right_inv_arrow = (parent, node) => {
{ x: w + h / 2, y: 0 },
{ x: w, y: -h / 2 },
{ x: w + h / 2, y: -h },
{ x: 0, y: -h }
{ x: 0, y: -h },
];
const el = insertPolygonShape(shapeSvg, w, h, points);
el.attr('style', node.style);
updateNodeBounds(node, el);
node.intersect = function(point) {
node.intersect = function (point) {
return intersect.polygon(node, points, point);
};
@ -246,7 +281,7 @@ const cylinder = (parent, node) => {
updateNodeBounds(node, el);
node.intersect = function(point) {
node.intersect = function (point) {
const pos = intersect.rect(node, point);
const x = pos.x - node.x;
@ -290,7 +325,7 @@ const rect = (parent, node) => {
updateNodeBounds(node, rect);
node.intersect = function(point) {
node.intersect = function (point) {
return intersect.rect(node, point);
};
@ -319,12 +354,20 @@ const rectWithTitle = (parent, node) => {
const label = shapeSvg.insert('g').attr('class', 'label');
const text2 = node.labelText.flat();
log.info('Label text', text2[0]);
const text2 = node.labelText.flat ? node.labelText.flat() : node.labelText;
// const text2 = typeof text2prim === 'object' ? text2prim[0] : text2prim;
const text = label.node().appendChild(createLabel(text2[0], node.labelStyle, true, true));
let title = '';
if (typeof text2 === 'object') {
title = text2[0];
} else {
title = text2;
}
log.info('Label text abc79', title, text2, typeof text2 === 'object');
const text = label.node().appendChild(createLabel(title, node.labelStyle, true, true));
let bbox;
if (getConfig().flowchart.htmlLabels) {
if (evaluate(getConfig().flowchart.htmlLabels)) {
const div = text.children[0];
const dv = select(text);
bbox = div.getBoundingClientRect();
@ -336,9 +379,11 @@ const rectWithTitle = (parent, node) => {
let titleBox = text.getBBox();
const descr = label
.node()
.appendChild(createLabel(textRows.join('<br/>'), node.labelStyle, true, true));
.appendChild(
createLabel(textRows.join ? textRows.join('<br/>') : textRows, node.labelStyle, true, true)
);
if (getConfig().flowchart.htmlLabels) {
if (evaluate(getConfig().flowchart.htmlLabels)) {
const div = descr.children[0];
const dv = select(descr);
bbox = div.getBoundingClientRect();
@ -393,7 +438,7 @@ const rectWithTitle = (parent, node) => {
updateNodeBounds(node, rect);
node.intersect = function(point) {
node.intersect = function (point) {
return intersect.rect(node, point);
};
@ -419,7 +464,7 @@ const stadium = (parent, node) => {
updateNodeBounds(node, rect);
node.intersect = function(point) {
node.intersect = function (point) {
return intersect.rect(node, point);
};
@ -443,7 +488,7 @@ const circle = (parent, node) => {
updateNodeBounds(node, circle);
node.intersect = function(point) {
node.intersect = function (point) {
log.info('Circle intersect', node, bbox.width / 2 + halfPadding, point);
return intersect.circle(node, bbox.width / 2 + halfPadding, point);
};
@ -466,14 +511,14 @@ const subroutine = (parent, node) => {
{ x: w + 8, y: 0 },
{ x: w + 8, y: -h },
{ x: -8, y: -h },
{ x: -8, y: 0 }
{ x: -8, y: 0 },
];
const el = insertPolygonShape(shapeSvg, w, h, points);
el.attr('style', node.style);
updateNodeBounds(node, el);
node.intersect = function(point) {
node.intersect = function (point) {
return intersect.polygon(node, points, point);
};
@ -488,15 +533,11 @@ const start = (parent, node) => {
const circle = shapeSvg.insert('circle', ':first-child');
// center the circle around its coordinate
circle
.attr('class', 'state-start')
.attr('r', 7)
.attr('width', 14)
.attr('height', 14);
circle.attr('class', 'state-start').attr('r', 7).attr('width', 14).attr('height', 14);
updateNodeBounds(node, circle);
node.intersect = function(point) {
node.intersect = function (point) {
return intersect.circle(node, 7, point);
};
@ -519,8 +560,6 @@ const forkJoin = (parent, node, dir) => {
const shape = shapeSvg
.append('rect')
.style('stroke', 'black')
.style('fill', 'black')
.attr('x', (-1 * width) / 2)
.attr('y', (-1 * height) / 2)
.attr('width', width)
@ -530,7 +569,7 @@ const forkJoin = (parent, node, dir) => {
updateNodeBounds(node, shape);
node.height = node.height + node.padding / 2;
node.width = node.width + node.padding / 2;
node.intersect = function(point) {
node.intersect = function (point) {
return intersect.rect(node, point);
};
@ -545,21 +584,13 @@ const end = (parent, node) => {
const innerCircle = shapeSvg.insert('circle', ':first-child');
const circle = shapeSvg.insert('circle', ':first-child');
circle
.attr('class', 'state-start')
.attr('r', 7)
.attr('width', 14)
.attr('height', 14);
circle.attr('class', 'state-start').attr('r', 7).attr('width', 14).attr('height', 14);
innerCircle
.attr('class', 'state-end')
.attr('r', 5)
.attr('width', 10)
.attr('height', 10);
innerCircle.attr('class', 'state-end').attr('r', 5).attr('width', 10).attr('height', 10);
updateNodeBounds(node, circle);
node.intersect = function(point) {
node.intersect = function (point) {
return intersect.circle(node, 7, point);
};
@ -602,7 +633,7 @@ const class_box = (parent, node) => {
.node()
.appendChild(createLabel(interfaceLabelText, node.labelStyle, true, true));
let interfaceBBox = interfaceLabel.getBBox();
if (getConfig().flowchart.htmlLabels) {
if (evaluate(getConfig().flowchart.htmlLabels)) {
const div = interfaceLabel.children[0];
const dv = select(interfaceLabel);
interfaceBBox = div.getBoundingClientRect();
@ -617,14 +648,18 @@ const class_box = (parent, node) => {
let classTitleString = node.classData.id;
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
.node()
.appendChild(createLabel(classTitleString, node.labelStyle, true, true));
select(classTitleLabel).attr('class', 'classTitle');
let classTitleBBox = classTitleLabel.getBBox();
if (getConfig().flowchart.htmlLabels) {
if (evaluate(getConfig().flowchart.htmlLabels)) {
const div = classTitleLabel.children[0];
const dv = select(classTitleLabel);
classTitleBBox = div.getBoundingClientRect();
@ -636,13 +671,16 @@ const class_box = (parent, node) => {
maxWidth = classTitleBBox.width;
}
const classAttributes = [];
node.classData.members.forEach(str => {
const parsedText = parseMember(str).displayText;
node.classData.members.forEach((str) => {
let parsedText = parseMember(str).displayText;
if (getConfig().flowchart.htmlLabels) {
parsedText = parsedText.replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
const lbl = labelContainer
.node()
.appendChild(createLabel(parsedText, node.labelStyle, true, true));
let bbox = lbl.getBBox();
if (getConfig().flowchart.htmlLabels) {
if (evaluate(getConfig().flowchart.htmlLabels)) {
const div = lbl.children[0];
const dv = select(lbl);
bbox = div.getBoundingClientRect();
@ -659,13 +697,24 @@ const class_box = (parent, node) => {
maxHeight += lineHeight;
const classMethods = [];
node.classData.methods.forEach(str => {
const parsedText = parseMember(str).displayText;
node.classData.methods.forEach((str) => {
const parsedInfo = parseMember(str);
let displayText = parsedInfo.displayText;
if (getConfig().flowchart.htmlLabels) {
displayText = displayText.replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
const lbl = labelContainer
.node()
.appendChild(createLabel(parsedText, node.labelStyle, true, true));
.appendChild(
createLabel(
displayText,
parsedInfo.cssStyle ? parsedInfo.cssStyle : node.labelStyle,
true,
true
)
);
let bbox = lbl.getBBox();
if (getConfig().flowchart.htmlLabels) {
if (evaluate(getConfig().flowchart.htmlLabels)) {
const div = lbl.children[0];
const dv = select(lbl);
bbox = div.getBoundingClientRect();
@ -714,7 +763,7 @@ const class_box = (parent, node) => {
verticalPos += lineHeight;
classAttributes.forEach(lbl => {
classAttributes.forEach((lbl) => {
select(lbl).attr(
'transform',
'translate( ' +
@ -736,7 +785,7 @@ const class_box = (parent, node) => {
verticalPos += lineHeight;
classMethods.forEach(lbl => {
classMethods.forEach((lbl) => {
select(lbl).attr(
'transform',
'translate( ' + -maxWidth / 2 + ', ' + ((-1 * maxHeight) / 2 + verticalPos) + ')'
@ -745,7 +794,7 @@ const class_box = (parent, node) => {
});
//
// let bbox;
// if (getConfig().flowchart.htmlLabels) {
// if (evaluate(getConfig().flowchart.htmlLabels)) {
// const div = interfaceLabel.children[0];
// const dv = select(interfaceLabel);
// bbox = div.getBoundingClientRect();
@ -761,7 +810,7 @@ const class_box = (parent, node) => {
// .node()
// .appendChild(createLabel(textRows.join('<br/>'), node.labelStyle, true, true));
// if (getConfig().flowchart.htmlLabels) {
// if (evaluate(getConfig().flowchart.htmlLabels)) {
// const div = descr.children[0];
// const dv = select(descr);
// bbox = div.getBoundingClientRect();
@ -815,7 +864,7 @@ const class_box = (parent, node) => {
updateNodeBounds(node, rect);
node.intersect = function(point) {
node.intersect = function (point) {
return intersect.rect(node, point);
};
@ -826,6 +875,7 @@ const shapes = {
question,
rect,
rectWithTitle,
choice,
circle,
stadium,
hexagon,
@ -842,7 +892,7 @@ const shapes = {
subroutine,
fork: forkJoin,
join: forkJoin,
class_box
class_box,
};
let nodeElems = {};
@ -882,19 +932,21 @@ export const clear = () => {
nodeElems = {};
};
export const positionNode = node => {
export const positionNode = (node) => {
const el = nodeElems[node.id];
log.trace(
'Transforming node',
node.diff,
node,
'translate(' + (node.x - node.width / 2 - 5) + ', ' + (node.y - node.height / 2 - 5) + ')'
'translate(' + (node.x - node.width / 2 - 5) + ', ' + node.width / 2 + ')'
);
const padding = 8;
const diff = node.diff || 0;
if (node.clusterNode) {
el.attr(
'transform',
'translate(' +
(node.x - node.width / 2 - padding) +
(node.x + diff - node.width / 2) +
', ' +
(node.y - node.height / 2 - padding) +
')'
@ -902,4 +954,5 @@ export const positionNode = node => {
} else {
el.attr('transform', 'translate(' + node.x + ', ' + node.y + ')');
}
return diff;
};

View File

@ -6,7 +6,7 @@
// Only add the number of markers that the diagram needs
const insertPatterns = (elem, patternArray, type, id) => {
patternArray.forEach(patternName => {
patternArray.forEach((patternName) => {
patterns[patternName](elem, type, id);
});
};
@ -49,6 +49,6 @@ const dots = (elem, type) => {
// TODO rename the class diagram markers to something shape descriptive and semanitc free
const patterns = {
dots
dots,
};
export default insertPatterns;

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