mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-10-02 13:49:37 +02:00
Compare commits
213 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0544dbe891 | ||
![]() |
6365cea0b2 | ||
![]() |
7fef13346e | ||
![]() |
81216e6ece | ||
![]() |
3fe7995060 | ||
![]() |
c441d04e8a | ||
![]() |
52d84a99ac | ||
![]() |
fcf20215a6 | ||
![]() |
aa2f9622f8 | ||
![]() |
1811318dea | ||
![]() |
5eb50cb2b6 | ||
![]() |
f6ef6ff7db | ||
![]() |
2f33a80e1e | ||
![]() |
363d49b655 | ||
![]() |
de8c6d5572 | ||
![]() |
9406bda93d | ||
![]() |
d17a447a5f | ||
![]() |
5b4e95484e | ||
![]() |
bebea41e19 | ||
![]() |
74c8e7fad9 | ||
![]() |
4b781d3827 | ||
![]() |
9fbcc5c32d | ||
![]() |
b73a6d84ee | ||
![]() |
2eaa7f1ab6 | ||
![]() |
608445e64f | ||
![]() |
1f4be77662 | ||
![]() |
0deae4abf9 | ||
![]() |
5b2f9351c7 | ||
![]() |
6fdf30357c | ||
![]() |
cf5d7478fc | ||
![]() |
9a0df5afb0 | ||
![]() |
813b2fcb38 | ||
![]() |
08cbc0f187 | ||
![]() |
d8251c8f79 | ||
![]() |
5ea70baa6f | ||
![]() |
d23ce9fb63 | ||
![]() |
ddf8016a0c | ||
![]() |
ab191abd5a | ||
![]() |
c2e5e94b37 | ||
![]() |
6a9b251be1 | ||
![]() |
6b5185abfb | ||
![]() |
2a41280076 | ||
![]() |
91d986970b | ||
![]() |
b4192bba7a | ||
![]() |
9fe0aa0604 | ||
![]() |
fc528749f8 | ||
![]() |
5c71a3c85b | ||
![]() |
94e768dd01 | ||
![]() |
0fb91d6bcc | ||
![]() |
02854881b4 | ||
![]() |
4254781391 | ||
![]() |
31f4f4096e | ||
![]() |
e95e016378 | ||
![]() |
c337c9128c | ||
![]() |
5a38562bfc | ||
![]() |
a3dd0e5f7d | ||
![]() |
fcd1e106a5 | ||
![]() |
346328156a | ||
![]() |
3239f99ea8 | ||
![]() |
93c32d3f29 | ||
![]() |
98449dac3f | ||
![]() |
32b60edda7 | ||
![]() |
823c95bd9c | ||
![]() |
e99d872f2b | ||
![]() |
de8f8b02dc | ||
![]() |
eec45dfff9 | ||
![]() |
cce86c8e96 | ||
![]() |
aabdc47c38 | ||
![]() |
cb07a729e5 | ||
![]() |
df10f7fbe7 | ||
![]() |
71c531240f | ||
![]() |
1e83207dac | ||
![]() |
3311fcdc8e | ||
![]() |
f368be925f | ||
![]() |
075c57ca06 | ||
![]() |
49fc80d506 | ||
![]() |
74fc2fcfa9 | ||
![]() |
7cc427e28d | ||
![]() |
87c571412c | ||
![]() |
ab093b2cde | ||
![]() |
bbc4ede768 | ||
![]() |
64c20dc528 | ||
![]() |
50ea9bda89 | ||
![]() |
2cf8c4e37a | ||
![]() |
fe4719f656 | ||
![]() |
1d43b7b316 | ||
![]() |
78e4fead49 | ||
![]() |
02d5143ff2 | ||
![]() |
d9c92b2c6d | ||
![]() |
27ac9bbaf3 | ||
![]() |
11cdd393f2 | ||
![]() |
1ca8578035 | ||
![]() |
2516718882 | ||
![]() |
5283314c4f | ||
![]() |
dcae8da0d1 | ||
![]() |
34f2a1a02f | ||
![]() |
ee5a68a23c | ||
![]() |
6c706ccd9f | ||
![]() |
94106f5825 | ||
![]() |
72ab2b8011 | ||
![]() |
8978ab5917 | ||
![]() |
94577316f9 | ||
![]() |
91650fb052 | ||
![]() |
e9aa037230 | ||
![]() |
871e6f691c | ||
![]() |
fe60836a89 | ||
![]() |
bea2e73b82 | ||
![]() |
481e55e8da | ||
![]() |
d26a67297a | ||
![]() |
753bd7e1d9 | ||
![]() |
b57492c1c6 | ||
![]() |
4ff5c3b455 | ||
![]() |
f62c47a757 | ||
![]() |
a85bb0d86f | ||
![]() |
5736d523dd | ||
![]() |
5004b5723d | ||
![]() |
ad2802d8e8 | ||
![]() |
3fedd452a5 | ||
![]() |
292bc3c4e5 | ||
![]() |
512ba8e733 | ||
![]() |
9a87ff684d | ||
![]() |
f79fc21bfc | ||
![]() |
ffddd58b6b | ||
![]() |
087e5eaa32 | ||
![]() |
cbd27831df | ||
![]() |
f6028b63b6 | ||
![]() |
a60e01db97 | ||
![]() |
68c2ea38c9 | ||
![]() |
3469cfca2f | ||
![]() |
afd189d24c | ||
![]() |
06cb09c267 | ||
![]() |
e461b57a48 | ||
![]() |
eca9d49575 | ||
![]() |
15a37a5062 | ||
![]() |
3f8f9eb92c | ||
![]() |
33de2bda9e | ||
![]() |
94d913fbab | ||
![]() |
beb1fcc176 | ||
![]() |
1e1a6e3a2d | ||
![]() |
6e7c21e439 | ||
![]() |
cfe9aaf639 | ||
![]() |
69e701befb | ||
![]() |
5174a085b7 | ||
![]() |
15fab69eca | ||
![]() |
20b103a0fb | ||
![]() |
8ebe7ee81a | ||
![]() |
1d747f664b | ||
![]() |
dbf5988c28 | ||
![]() |
31ab0e4b7d | ||
![]() |
35ea7083bb | ||
![]() |
bf90e8bf44 | ||
![]() |
b1305644f4 | ||
![]() |
34707a057b | ||
![]() |
f5e90252f1 | ||
![]() |
e75acf69aa | ||
![]() |
3ad3fc2622 | ||
![]() |
a59468d6c1 | ||
![]() |
86e63b1614 | ||
![]() |
3f8f9f6711 | ||
![]() |
d01f494277 | ||
![]() |
4db525c6a9 | ||
![]() |
8b5f8b0cb4 | ||
![]() |
d0c9b5e98f | ||
![]() |
e313625ccb | ||
![]() |
7dead548f3 | ||
![]() |
8db46ff762 | ||
![]() |
93f54a997a | ||
![]() |
1353491952 | ||
![]() |
00802ffe7a | ||
![]() |
78e556aaf7 | ||
![]() |
e34988d65a | ||
![]() |
07f5c7c89c | ||
![]() |
7319d8941a | ||
![]() |
3d7933135b | ||
![]() |
a778472461 | ||
![]() |
cbe2a7446d | ||
![]() |
8251dc5cd1 | ||
![]() |
5a4103a248 | ||
![]() |
d7996f5c1a | ||
![]() |
db4229f033 | ||
![]() |
e103664963 | ||
![]() |
fbf3936ddc | ||
![]() |
62d03f1976 | ||
![]() |
f3ea159c6b | ||
![]() |
3c99294a3a | ||
![]() |
7a2a8cffbb | ||
![]() |
6d90f87b2f | ||
![]() |
f506d24a82 | ||
![]() |
ddb0d23ca7 | ||
![]() |
763be9bb95 | ||
![]() |
77109144e7 | ||
![]() |
840e7bd985 | ||
![]() |
a6c12f4b25 | ||
![]() |
e8e9a4d07b | ||
![]() |
ba00182ce4 | ||
![]() |
2ad78ee3b8 | ||
![]() |
4995d59499 | ||
![]() |
d58ef7aa36 | ||
![]() |
dc59632fb3 | ||
![]() |
1542e15a1b | ||
![]() |
5b5be40dd5 | ||
![]() |
1ecf0f4c23 | ||
![]() |
fa7d1ac554 | ||
![]() |
48ce7a9b78 | ||
![]() |
09bf54f9af | ||
![]() |
43b9bcdb0b | ||
![]() |
aac915b285 | ||
![]() |
7208f045c1 | ||
![]() |
f7a3c42da1 | ||
![]() |
4d1c53eb1e | ||
![]() |
7bcc9b19ac | ||
![]() |
7cfc729679 | ||
![]() |
ec3b68ad28 |
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [knsv]
|
||||
#patreon: # Replace with a single Patreon username
|
||||
#open_collective: # Replace with a single Open Collective username
|
||||
#ko_fi: # Replace with a single Ko-fi username
|
||||
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
#liberapay: # Replace with a single Liberapay username
|
||||
#issuehunt: # Replace with a single IssueHunt username
|
||||
#otechie: # Replace with a single Otechie username
|
||||
#custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
3
.github/pr-labeler.yml
vendored
Normal file
3
.github/pr-labeler.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
'Type: Bug / Error': 'bug/*'
|
||||
'Type: Enhancement': 'feature/*'
|
||||
'Type: Other': 'other/*'
|
7
.github/pull_request_template.md
vendored
Normal file
7
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
## Summary
|
||||
Brief description about the content of your PR.
|
||||
|
||||
## Design Descisions
|
||||
Describe the way your implementation works or what design descisions you made if applicable.
|
||||
|
||||
Resolves #<your issue id here>
|
25
.github/release-drafter.yml
vendored
Normal file
25
.github/release-drafter.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name-template: '$NEXT_PATCH_VERSION'
|
||||
tag-template: '$NEXT_PATCH_VERSION'
|
||||
categories:
|
||||
- title: '🚀 Features'
|
||||
labels:
|
||||
- 'Type: Enhancement'
|
||||
- title: '🐛 Bug Fixes'
|
||||
labels:
|
||||
- 'Type: Bug / Error'
|
||||
- title: '🧰 Maintenance'
|
||||
label: 'Type: Other'
|
||||
change-template: '- $TITLE (#$NUMBER) @$AUTHOR'
|
||||
sort-by: title
|
||||
sort-direction: ascending
|
||||
branches:
|
||||
- develop
|
||||
exclude-labels:
|
||||
- 'Skip changelog'
|
||||
no-changes-template: 'This release contains minor changes and bugfixes.'
|
||||
template: |
|
||||
# Release Notes
|
||||
|
||||
$CHANGES
|
||||
|
||||
🎉 **Thanks to all contributors helping with this release!** 🎉
|
58
.github/workflows/build.yml
vendored
Normal file
58
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
name: Build
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [10.x, 12.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- name: Setup Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
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
|
||||
|
||||
- name: Run Build
|
||||
run: yarn build
|
||||
|
||||
- name: Run Unit Tests
|
||||
run: |
|
||||
yarn test --coverage
|
||||
|
||||
- name: Upload Test Results
|
||||
uses: coverallsapp/github-action@v1.0.1
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
parallel: true
|
||||
|
||||
- name: Run E2E Tests
|
||||
run: yarn e2e
|
||||
env:
|
||||
PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}
|
||||
CYPRESS_CACHE_FOLDER: .cache/Cypress
|
||||
|
||||
- name: Post Upload Test Results
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
parallel-finished: true
|
13
.github/workflows/pr-labeler.yml
vendored
Normal file
13
.github/workflows/pr-labeler.yml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
name: Apply labels to PR
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
pr-labeler:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Label PR
|
||||
uses: TimonVS/pr-labeler-action@v3
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
15
.github/workflows/release-draft.yml
vendored
Normal file
15
.github/workflows/release-draft.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
name: Draft Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
draft-release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Draft Release
|
||||
uses: toolmantim/release-drafter@v5.2.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
@@ -8,15 +8,12 @@ on:
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [10.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Setup Node.js ${{ matrix.node-version }}
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
node-version: 10.x
|
||||
- name: Install Yarn
|
||||
run: npm i yarn --global
|
||||
|
||||
@@ -24,7 +21,7 @@ jobs:
|
||||
run: npm i json --global
|
||||
|
||||
- name: Install Packages
|
||||
run: yarn install
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Publish
|
||||
run: |
|
||||
|
46
.github/workflows/release-publish.yml
vendored
Normal file
46
.github/workflows/release-publish.yml
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
name: Publish release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: fregante/setup-git-token@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 10.x
|
||||
- name: Install Yarn
|
||||
run: npm i yarn --global
|
||||
|
||||
- name: Install Json
|
||||
run: npm i json --global
|
||||
|
||||
- name: Install Packages
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Prepare release
|
||||
run: |
|
||||
VERSION=${GITHUB_REF:10}
|
||||
echo "Preparing release $VERSION"
|
||||
git checkout -t origin/release/$VERSION
|
||||
npm version --no-git-tag-version --allow-same-version $VERSION
|
||||
git add package.json
|
||||
git commit -m "Bump version $VERSION"
|
||||
git checkout -t origin/master
|
||||
git merge -m "Release $VERSION" --no-ff release/$VERSION
|
||||
git push --no-verify
|
||||
|
||||
- name: Publish
|
||||
run: |
|
||||
npm set //registry.npmjs.org/:_authToken $NPM_TOKEN
|
||||
npm publish
|
||||
env:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
8
.vscode/settings.json
vendored
8
.vscode/settings.json
vendored
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"typescript.format.enable": false,
|
||||
"typescript.reportStyleChecksAsWarnings": false,
|
||||
"typescript.validate.enable": false,
|
||||
"javascript.validate.enable": false,
|
||||
"editor.formatOnSave": false,
|
||||
"editor.snippetSuggestions": "top"
|
||||
}
|
12
README.md
12
README.md
@@ -27,7 +27,7 @@ C -->|One| D[Result 1]
|
||||
C -->|Two| E[Result 2]
|
||||
</pre></td>
|
||||
<td align="center">
|
||||
<img src="./img/gray-flow.png" />
|
||||
<img src="https://raw.githubusercontent.com/mermaid-js/mermaid/master/img/gray-flow.png" />
|
||||
</td>
|
||||
</tr>
|
||||
<!-- </Flowchart> -->
|
||||
@@ -49,7 +49,7 @@ John->>Bob: How about you?
|
||||
Bob-->>John: Jolly good!
|
||||
</pre></td>
|
||||
<td align="center">
|
||||
<img src="./img/gray-sequence.png" />
|
||||
<img src="https://raw.githubusercontent.com/mermaid-js/mermaid/master/img/gray-sequence.png" />
|
||||
</td>
|
||||
</tr>
|
||||
<!-- </Sequence> -->
|
||||
@@ -70,7 +70,7 @@ Parallel 3 : des5, after des3, 1d
|
||||
Parallel 4 : des6, after des4, 1d
|
||||
</pre></td>
|
||||
<td align="center">
|
||||
<img src="./img/gray-gantt.png" />
|
||||
<img src="https://raw.githubusercontent.com/mermaid-js/mermaid/master/img/gray-gantt.png" />
|
||||
</td>
|
||||
</tr>
|
||||
<!-- </Gantt> -->
|
||||
@@ -99,7 +99,7 @@ class Class10 {
|
||||
}
|
||||
</pre></td>
|
||||
<td align="center">
|
||||
<img src="./img/gray-class.png" />
|
||||
<img src="https://raw.githubusercontent.com/mermaid-js/mermaid/master/img/gray-class.png" />
|
||||
</td>
|
||||
</tr>
|
||||
<!-- </Class> -->
|
||||
@@ -119,7 +119,7 @@ Moving --> Crash
|
||||
Crash --> [*]
|
||||
</pre></td>
|
||||
<td align="center">
|
||||
<img src="./img/gray-state.png" />
|
||||
<img src="https://raw.githubusercontent.com/mermaid-js/mermaid/master/img/gray-state.png" />
|
||||
</td>
|
||||
</tr>
|
||||
<!-- </State> -->
|
||||
@@ -136,7 +136,7 @@ pie
|
||||
"Rats" : 15
|
||||
</pre></td>
|
||||
<td align="center">
|
||||
<img src="./img/gray-pie.png" />
|
||||
<img src="https://raw.githubusercontent.com/mermaid-js/mermaid/master/img/gray-pie.png" />
|
||||
</td>
|
||||
</tr>
|
||||
<!-- </Pie> -->
|
||||
|
@@ -3,9 +3,7 @@ module.exports = {
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
targets: {
|
||||
node: 'current'
|
||||
}
|
||||
targets: "defaults, ie >= 11, current node"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
@@ -26,3 +26,9 @@ export const imgSnapshotTest = (graphStr, options, api) => {
|
||||
cy.get('svg');
|
||||
cy.percySnapshot();
|
||||
};
|
||||
|
||||
export const renderGraph = (graphStr, options, api) => {
|
||||
const url = mermaidUrl(graphStr, options, api);
|
||||
|
||||
cy.visit(url);
|
||||
};
|
||||
|
100
cypress/integration/other/configuration.spec.js
Normal file
100
cypress/integration/other/configuration.spec.js
Normal file
@@ -0,0 +1,100 @@
|
||||
import { renderGraph } from '../../helpers/util';
|
||||
/* eslint-env jest */
|
||||
describe('Configuration', () => {
|
||||
describe('arrowMarkerAbsolute', () => {
|
||||
it('should handle default value false of arrowMarkerAbsolute', () => {
|
||||
renderGraph(
|
||||
`graph TD
|
||||
A[Christmas] -->|Get money| B(Go shopping)
|
||||
B --> C{Let me think}
|
||||
C -->|One| D[Laptop]
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
`,
|
||||
{ }
|
||||
);
|
||||
|
||||
// Check the marker-end property to make sure it is properly set to
|
||||
// start with #
|
||||
cy.get('.edgePath path').first().should('have.attr', 'marker-end')
|
||||
.should('exist')
|
||||
.and('include', 'url(#');
|
||||
});
|
||||
it('should handle default value false of arrowMarkerAbsolute', () => {
|
||||
renderGraph(
|
||||
`graph TD
|
||||
A[Christmas] -->|Get money| B(Go shopping)
|
||||
B --> C{Let me think}
|
||||
C -->|One| D[Laptop]
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
`,
|
||||
{ }
|
||||
);
|
||||
|
||||
// Check the marker-end property to make sure it is properly set to
|
||||
// start with #
|
||||
cy.get('.edgePath path').first().should('have.attr', 'marker-end')
|
||||
.should('exist')
|
||||
.and('include', 'url(#');
|
||||
});
|
||||
it('should handle arrowMarkerAbsolute excplicitly set to false', () => {
|
||||
renderGraph(
|
||||
`graph TD
|
||||
A[Christmas] -->|Get money| B(Go shopping)
|
||||
B --> C{Let me think}
|
||||
C -->|One| D[Laptop]
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
`,
|
||||
{
|
||||
arrowMarkerAbsolute: false
|
||||
}
|
||||
);
|
||||
|
||||
// Check the marker-end property to make sure it is properly set to
|
||||
// start with #
|
||||
cy.get('.edgePath path').first().should('have.attr', 'marker-end')
|
||||
.should('exist')
|
||||
.and('include', 'url(#');
|
||||
});
|
||||
it('should handle arrowMarkerAbsolute excplicitly set to "false" as false', () => {
|
||||
renderGraph(
|
||||
`graph TD
|
||||
A[Christmas] -->|Get money| B(Go shopping)
|
||||
B --> C{Let me think}
|
||||
C -->|One| D[Laptop]
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
`,
|
||||
{
|
||||
arrowMarkerAbsolute: "false"
|
||||
}
|
||||
);
|
||||
|
||||
// Check the marker-end property to make sure it is properly set to
|
||||
// start with #
|
||||
cy.get('.edgePath path').first().should('have.attr', 'marker-end')
|
||||
.should('exist')
|
||||
.and('include', 'url(#');
|
||||
});
|
||||
it('should handle arrowMarkerAbsolute set to true', () => {
|
||||
renderGraph(
|
||||
`graph TD
|
||||
A[Christmas] -->|Get money| B(Go shopping)
|
||||
B --> C{Let me think}
|
||||
C -->|One| D[Laptop]
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
`,
|
||||
{
|
||||
arrowMarkerAbsolute: true
|
||||
}
|
||||
);
|
||||
|
||||
cy.get('.edgePath path').first().should('have.attr', 'marker-end')
|
||||
.should('exist')
|
||||
.and('include', 'url(http://localhost');
|
||||
});
|
||||
});
|
||||
});
|
@@ -16,7 +16,7 @@ describe('Interaction', () => {
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('g#s1Function')
|
||||
.find('g[id="1Function"]')
|
||||
.click();
|
||||
|
||||
cy.get('.created-by-click').should('have.text', 'Clicked By Flow');
|
||||
@@ -38,7 +38,7 @@ describe('Interaction', () => {
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('g#s2URL')
|
||||
.find('g[id="2URL"]')
|
||||
.click();
|
||||
|
||||
cy.location().should(location => {
|
||||
@@ -108,7 +108,7 @@ describe('Interaction', () => {
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('g#s1Function')
|
||||
.find('g[id="1Function"]')
|
||||
.click();
|
||||
|
||||
cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow');
|
||||
@@ -130,7 +130,7 @@ describe('Interaction', () => {
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('g#s2URL')
|
||||
.find('g[id="2URL"]')
|
||||
.click();
|
||||
|
||||
cy.location().should(location => {
|
||||
@@ -200,7 +200,7 @@ describe('Interaction', () => {
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('g#s1Function')
|
||||
.find('g[id="1Function"]')
|
||||
.click();
|
||||
|
||||
cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow');
|
||||
|
@@ -9,8 +9,27 @@ describe('XSS', () => {
|
||||
const url = mermaidUrl(str,{}, true);
|
||||
|
||||
cy.visit(url);
|
||||
cy.wait(1000).then(()=>{
|
||||
cy.get('.mermaid').should('exist');
|
||||
});
|
||||
cy.get('svg')
|
||||
cy.percySnapshot()
|
||||
// cy.percySnapshot()
|
||||
|
||||
})
|
||||
it('should handle xss in tags in non-html mode', () => {
|
||||
const str = 'eyJjb2RlIjoiXG5ncmFwaCBMUlxuICAgICAgQi0tPkQoPGltZyBvbmVycm9yPWxvY2F0aW9uPWBqYXZhc2NyaXB0XFx1MDAzYXhzc0F0dGFja1xcdTAwMjhkb2N1bWVudC5kb21haW5cXHUwMDI5YCBzcmM9eD4pOyIsIm1lcm1haWQiOnsidGhlbWUiOiJkZWZhdWx0IiwiZmxvd2NoYXJ0Ijp7Imh0bWxMYWJlbHMiOmZhbHNlfX19';
|
||||
|
||||
const url = mermaidUrl(str,{
|
||||
"theme": "default",
|
||||
"flowchart": {
|
||||
"htmlMode": false
|
||||
}
|
||||
}, true);
|
||||
|
||||
cy.visit(url);
|
||||
// cy.get('svg')
|
||||
// cy.percySnapshot()
|
||||
cy.get('.malware').should('not.exist');
|
||||
|
||||
})
|
||||
})
|
||||
|
@@ -2,7 +2,7 @@
|
||||
import { imgSnapshotTest } from '../../helpers/util';
|
||||
|
||||
describe('Class diagram', () => {
|
||||
it('should render a simple class diagram', () => {
|
||||
it('1: should render a simple class diagram', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
classDiagram
|
||||
@@ -19,6 +19,9 @@ describe('Class diagram', () => {
|
||||
Class01 : size()
|
||||
Class01 : int chimp
|
||||
Class01 : int gorilla
|
||||
Class01 : -int privateChimp
|
||||
Class01 : +int publicGorilla
|
||||
Class01 : #int protectedMarmoset
|
||||
Class08 <--> C2: Cool label
|
||||
class Class10 {
|
||||
<<service>>
|
||||
@@ -30,7 +33,8 @@ describe('Class diagram', () => {
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a simple class diagrams with cardinality', () => {
|
||||
|
||||
it('2: should render a simple class diagrams with cardinality', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
classDiagram
|
||||
@@ -58,4 +62,170 @@ describe('Class diagram', () => {
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('should render a simple class diagram with different visibilities', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
classDiagram
|
||||
Class01 <|-- AveryLongClass : Cool
|
||||
<<interface>> Class01
|
||||
Class01 : -int privateMethod()
|
||||
Class01 : +int publicMethod()
|
||||
Class01 : #int protectedMethod()
|
||||
Class01 : -int privateChimp
|
||||
Class01 : +int publicGorilla
|
||||
Class01 : #int protectedMarmoset
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('should render multiple class diagrams', () => {
|
||||
imgSnapshotTest(
|
||||
[
|
||||
`
|
||||
classDiagram
|
||||
Class01 "1" <|--|> "*" AveryLongClass : Cool
|
||||
<<interface>> 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 {
|
||||
<<service>>
|
||||
int id
|
||||
test()
|
||||
}
|
||||
`,
|
||||
`
|
||||
classDiagram
|
||||
Class01 "1" <|--|> "*" AveryLongClass : Cool
|
||||
<<interface>> 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 {
|
||||
<<service>>
|
||||
int id
|
||||
test()
|
||||
}
|
||||
`,
|
||||
],
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('4: should render a simple class diagram with comments', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
classDiagram
|
||||
%% this is a comment
|
||||
Class01 <|-- AveryLongClass : Cool
|
||||
<<interface>> 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 {
|
||||
<<service>>
|
||||
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~ {
|
||||
<<service>>
|
||||
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~ {
|
||||
<<service>>
|
||||
int id
|
||||
test()
|
||||
}
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
});
|
||||
|
@@ -2,19 +2,20 @@
|
||||
import { imgSnapshotTest } from '../../helpers/util';
|
||||
|
||||
describe('State diagram', () => {
|
||||
it('should render a flowchart full of circles', () => {
|
||||
it('should render a state with states in it', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
stateDiagram
|
||||
State1: The state with a note
|
||||
note right of State1
|
||||
Important information! You\ncan write
|
||||
notes with multiple lines...
|
||||
Here is another line...
|
||||
And another line...
|
||||
end note
|
||||
stateDiagram
|
||||
state PersonalizedCockpit {
|
||||
Other
|
||||
state Parent {
|
||||
C
|
||||
}
|
||||
}
|
||||
`,
|
||||
{}
|
||||
{
|
||||
logLevel: 0,
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@@ -14,6 +14,7 @@ describe('Flowcart', () => {
|
||||
{ flowchart: { htmlLabels: false } }
|
||||
);
|
||||
});
|
||||
|
||||
it('2: should render a simple flowchart with htmlLabels', () => {
|
||||
imgSnapshotTest(
|
||||
`graph TD
|
||||
@@ -26,6 +27,7 @@ describe('Flowcart', () => {
|
||||
{ flowchart: { htmlLabels: true } }
|
||||
);
|
||||
});
|
||||
|
||||
it('3: should render a simple flowchart with line breaks', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
@@ -99,6 +101,7 @@ describe('Flowcart', () => {
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('6: should render a flowchart full of icons', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
@@ -178,6 +181,7 @@ describe('Flowcart', () => {
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('8: should render subgraphs', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
@@ -190,7 +194,7 @@ describe('Flowcart', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('9: should render subgraphs with a title startign with a digit', () => {
|
||||
it('9: should render subgraphs with a title starting with a digit', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
graph TB
|
||||
@@ -237,7 +241,7 @@ describe('Flowcart', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('11: should render a flowchart with ling sames and class definitoins', () => {
|
||||
it('11: should render a flowchart with long names and class definitions', () => {
|
||||
imgSnapshotTest(
|
||||
`graph LR
|
||||
sid-B3655226-6C29-4D00-B685-3D5C734DC7E1["
|
||||
@@ -356,4 +360,72 @@ describe('Flowcart', () => {
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('13: should render hexagons', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
graph TD
|
||||
A[Christmas] -->|Get money| B(Go shopping)
|
||||
B --> C{{Let me think...<br />Do I want something for work,<br />something to spend every free second with,<br />or something to get around?}}
|
||||
C -->|One| D[Laptop]
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[Car]
|
||||
click A "index.html#link-clicked" "link test"
|
||||
click B testClick "click test"
|
||||
classDef someclass fill:#f96;
|
||||
class A someclass;
|
||||
`,
|
||||
{
|
||||
listUrl: false,
|
||||
listId: 'color styling',
|
||||
logLevel: 0
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('14: should render a simple flowchart with comments', () => {
|
||||
imgSnapshotTest(
|
||||
`graph TD
|
||||
A[Christmas] -->|Get money| B(Go shopping)
|
||||
B --> C{Let me think}
|
||||
%% this is a comment
|
||||
C -->|One| D[Laptop]
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
`,
|
||||
{ flowchart: { htmlLabels: false } }
|
||||
);
|
||||
});
|
||||
it('15: Render Stadium shape', () => {
|
||||
imgSnapshotTest(
|
||||
` graph TD
|
||||
A([stadium shape test])
|
||||
A -->|Get money| B([Go shopping])
|
||||
B --> C([Let me think...<br />Do I want something for work,<br />something to spend every free second with,<br />or something to get around?])
|
||||
C -->|One| D([Laptop])
|
||||
C -->|Two| E([iPhone])
|
||||
C -->|Three| F([Car<br/>wroom wroom])
|
||||
click A "index.html#link-clicked" "link test"
|
||||
click B testClick "click test"
|
||||
classDef someclass fill:#f96;
|
||||
class A someclass;`,
|
||||
{ flowchart: { htmlLabels: false } }
|
||||
);
|
||||
});
|
||||
it('16: Render Stadium shape', () => {
|
||||
imgSnapshotTest(
|
||||
`graph LR
|
||||
A1[Multi<br>Line] -->|Multi<br>Line| B1(Multi<br>Line)
|
||||
C1[Multi<br/>Line] -->|Multi<br/>Line| D1(Multi<br/>Line)
|
||||
E1[Multi<br />Line] -->|Multi<br />Line| F1(Multi<br />Line)
|
||||
A2[Multi<br>Line] -->|Multi<br>Line| B2(Multi<br>Line)
|
||||
C2[Multi<br/>Line] -->|Multi<br/>Line| D2(Multi<br/>Line)
|
||||
E2[Multi<br />Line] -->|Multi<br />Line| F2(Multi<br />Line)
|
||||
linkStyle 0 stroke:DarkGray,stroke-width:2px
|
||||
linkStyle 1 stroke:DarkGray,stroke-width:2px
|
||||
linkStyle 2 stroke:DarkGray,stroke-width:2px
|
||||
`,
|
||||
{ flowchart: { htmlLabels: false } }
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@@ -38,4 +38,20 @@ describe('Sequencediagram', () => {
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('Multiple dependencies syntax', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
gantt
|
||||
dateFormat YYYY-MM-DD
|
||||
axisFormat %d/%m
|
||||
title Adding GANTT diagram to mermaid
|
||||
excludes weekdays 2014-01-10
|
||||
|
||||
apple :a, 2017-07-20, 1w
|
||||
banana :crit, b, 2017-07-23, 1d
|
||||
cherry :active, c, after b a, 1d
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@@ -2,20 +2,20 @@
|
||||
import { imgSnapshotTest } from '../../helpers/util.js';
|
||||
|
||||
describe('Sequencediagram', () => {
|
||||
it('should render a simple git graph', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
gitGraph:
|
||||
commit
|
||||
branch newbranch
|
||||
checkout newbranch
|
||||
commit
|
||||
commit
|
||||
checkout master
|
||||
commit
|
||||
commit
|
||||
merge newbranch`,
|
||||
{ logLevel: 0 }
|
||||
);
|
||||
});
|
||||
// it('should render a simple git graph', () => {
|
||||
// imgSnapshotTest(
|
||||
// `
|
||||
// gitGraph:
|
||||
// commit
|
||||
// branch newbranch
|
||||
// checkout newbranch
|
||||
// commit
|
||||
// commit
|
||||
// checkout master
|
||||
// commit
|
||||
// commit
|
||||
// merge newbranch`,
|
||||
// { logLevel: 0 }
|
||||
// );
|
||||
// });
|
||||
});
|
||||
|
@@ -106,6 +106,22 @@ describe('State diagram', () => {
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a note with multiple lines in it', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
stateDiagram
|
||||
State1: The state with a note
|
||||
note right of State1
|
||||
Important information! You\ncan write
|
||||
notes with multiple lines...
|
||||
Here is another line...
|
||||
And another line...
|
||||
end note
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('should render a states with descriptions including multi-line descriptions', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
@@ -276,4 +292,33 @@ describe('State diagram', () => {
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a state with states in it', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
stateDiagram
|
||||
state PilotCockpit {
|
||||
state Parent {
|
||||
C
|
||||
}
|
||||
}
|
||||
`,
|
||||
{
|
||||
logLevel: 0,
|
||||
}
|
||||
);
|
||||
});
|
||||
it('Simplest compone state', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
stateDiagram
|
||||
state Parent {
|
||||
C
|
||||
}
|
||||
`,
|
||||
{
|
||||
logLevel: 0,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
48
cypress/platform/current.html
Normal file
48
cypress/platform/current.html
Normal file
@@ -0,0 +1,48 @@
|
||||
<html>
|
||||
<head>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<style>
|
||||
body {background: white}
|
||||
h1 { color: white;}
|
||||
.arrowheadPath {fill: red;}
|
||||
|
||||
.edgePath .path {stroke: red;}
|
||||
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>info below</h1>
|
||||
<div style="display: flex;width: 100%; height: 100%">
|
||||
<div class="mermaid" style="width: 100%; height: 100%">gantt
|
||||
dateFormat YYYY-MM-DD
|
||||
axisFormat %d/%m
|
||||
title Adding GANTT diagram to mermaid
|
||||
excludes weekdays 2014-01-10
|
||||
|
||||
apple :a, 2017-07-20, 1w
|
||||
banana :crit, b, 2017-07-23, 1d
|
||||
cherry :active, c, after b a, 1d
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script src="./mermaid.js"></script>
|
||||
<script>
|
||||
mermaid.initialize({
|
||||
// theme: 'dark',
|
||||
// arrowMarkerAbsolute: true,
|
||||
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
|
||||
logLevel: 3,
|
||||
flowchart: { curve: 'linear', "htmlLabels": false },
|
||||
// gantt: { axisFormat: '%m/%d/%Y' },
|
||||
sequence: { actorMargin: 50 },
|
||||
// sequenceDiagram: { actorMargin: 300 } // deprecated
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@@ -4,9 +4,8 @@
|
||||
<link href="https://fonts.googleapis.com/css?family=Mansalva&display=swap" rel="stylesheet" />
|
||||
<style>
|
||||
body {
|
||||
/* font-family: 'Mansalva', cursive;
|
||||
font-family: 'Mansalva', cursive; */
|
||||
font-family: 'times';
|
||||
/* font-family: 'Mansalva', cursive;*/
|
||||
font-family: 'Mansalva', cursive;
|
||||
}
|
||||
/* .mermaid-main-font {
|
||||
font-family: "trebuchet ms", verdana, arial;
|
||||
|
@@ -14,13 +14,23 @@ const contentLoaded = function() {
|
||||
const graphObj = JSON.parse(Base64.decode(graphBase64));
|
||||
// const graph = 'hello'
|
||||
console.log(graphObj);
|
||||
const div = document.createElement('div');
|
||||
div.id = 'block';
|
||||
div.className = 'mermaid';
|
||||
div.innerHTML = graphObj.code;
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
if (Array.isArray(graphObj.code)) {
|
||||
const numCodes = graphObj.code.length;
|
||||
for (let i = 0; i < numCodes; i++) {
|
||||
const div = document.createElement('div');
|
||||
div.id = 'block' + i;
|
||||
div.className = 'mermaid';
|
||||
div.innerHTML = graphObj.code[i];
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
}
|
||||
} else {
|
||||
const div = document.createElement('div');
|
||||
div.id = 'block';
|
||||
div.className = 'mermaid';
|
||||
div.innerHTML = graphObj.code;
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
}
|
||||
global.mermaid.initialize(graphObj.mermaid);
|
||||
// console.log('graphObj.mermaid', graphObj.mermaid)
|
||||
global.mermaid.init();
|
||||
}
|
||||
};
|
||||
@@ -31,23 +41,53 @@ const contentLoadedApi = function() {
|
||||
const graphBase64 = document.location.href.substr(pos);
|
||||
const graphObj = JSON.parse(Base64.decode(graphBase64));
|
||||
// const graph = 'hello'
|
||||
const div = document.createElement('div');
|
||||
div.id = 'block';
|
||||
div.className = 'mermaid';
|
||||
// div.innerHTML = graphObj.code
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
global.mermaid.initialize(graphObj.mermaid);
|
||||
if (Array.isArray(graphObj.code)) {
|
||||
const numCodes = graphObj.code.length;
|
||||
const divs = [];
|
||||
let div;
|
||||
for (let i = 0; i < numCodes; i++) {
|
||||
div = document.createElement('div');
|
||||
div.id = 'block' + i;
|
||||
div.className = 'mermaid';
|
||||
// div.innerHTML = graphObj.code
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
divs[i] = div;
|
||||
}
|
||||
|
||||
mermaid2.render(
|
||||
'newid',
|
||||
graphObj.code,
|
||||
(svgCode, bindFunctions) => {
|
||||
div.innerHTML = svgCode;
|
||||
mermaid2.initialize(graphObj.mermaid);
|
||||
|
||||
bindFunctions(div);
|
||||
},
|
||||
div
|
||||
);
|
||||
for (let i = 0; i < numCodes; i++) {
|
||||
mermaid2.render(
|
||||
'newid' + i,
|
||||
graphObj.code[i],
|
||||
(svgCode, bindFunctions) => {
|
||||
div.innerHTML = svgCode;
|
||||
|
||||
bindFunctions(div);
|
||||
},
|
||||
divs[i]
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const div = document.createElement('div');
|
||||
div.id = 'block';
|
||||
div.className = 'mermaid';
|
||||
// div.innerHTML = graphObj.code
|
||||
console.warn('graphObj.mermaid', graphObj.mermaid);
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
mermaid2.initialize(graphObj.mermaid);
|
||||
|
||||
mermaid2.render(
|
||||
'newid',
|
||||
graphObj.code,
|
||||
(svgCode, bindFunctions) => {
|
||||
div.innerHTML = svgCode;
|
||||
|
||||
if (bindFunctions) bindFunctions(div);
|
||||
},
|
||||
div
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -28,7 +28,10 @@
|
||||
div.id = 'the-malware'
|
||||
div.className = 'malware'
|
||||
div.innerHTML = 'XSS Succeeded'
|
||||
document.getElementsByTagName('body')[0].appendChild(div)
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
// const el = document.querySelector('.mermaid');
|
||||
// el.parentNode.removeChild(el);
|
||||
throw new Error('XSS Succeded');
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
68
dist/index.html
vendored
68
dist/index.html
vendored
@@ -300,6 +300,31 @@ click B testClick "click test"
|
||||
classDef someclass fill:#f96;
|
||||
class A someclass;
|
||||
</div>
|
||||
<div class="mermaid">
|
||||
graph TD
|
||||
A([stadium shape test])
|
||||
A -->|Get money| B([Go shopping])
|
||||
B --> C([Let me think...<br />Do I want something for work,<br />something to spend every free second with,<br />or something to get around?])
|
||||
C -->|One| D([Laptop])
|
||||
C -->|Two| E([iPhone])
|
||||
C -->|Three| F([Car<br/>wroom wroom])
|
||||
click A "index.html#link-clicked" "link test"
|
||||
click B testClick "click test"
|
||||
classDef someclass fill:#f96;
|
||||
class A someclass;
|
||||
</div>
|
||||
<div class="mermaid">
|
||||
graph LR
|
||||
A1[Multi<br>Line] -->|Multi<br>Line| B1(Multi<br>Line)
|
||||
C1[Multi<br/>Line] -->|Multi<br/>Line| D1(Multi<br/>Line)
|
||||
E1[Multi<br />Line] -->|Multi<br />Line| F1(Multi<br />Line)
|
||||
A2[Multi<br>Line] -->|Multi<br>Line| B2(Multi<br>Line)
|
||||
C2[Multi<br/>Line] -->|Multi<br/>Line| D2(Multi<br/>Line)
|
||||
E2[Multi<br />Line] -->|Multi<br />Line| F2(Multi<br />Line)
|
||||
linkStyle 0 stroke:DarkGray,stroke-width:2px
|
||||
linkStyle 1 stroke:DarkGray,stroke-width:2px
|
||||
linkStyle 2 stroke:DarkGray,stroke-width:2px
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
@@ -408,9 +433,9 @@ Class09 "0" --* "1..n" C3
|
||||
Class09 --|> Class07
|
||||
Class07 : equals()
|
||||
Class07 : Object[] elementData
|
||||
Class01 : size()
|
||||
Class01 : int chimp
|
||||
Class01 : int gorilla
|
||||
Class01 : #size()
|
||||
Class01 : -int chimp
|
||||
Class01 : +int gorilla
|
||||
Class08 <--> C2: Cool label
|
||||
class Class10 {
|
||||
<<service>>
|
||||
@@ -418,6 +443,43 @@ class Class10 {
|
||||
size()
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="mermaid">
|
||||
classDiagram
|
||||
class Class01~T~
|
||||
Class01 : #size()
|
||||
Class01 : -int chimp
|
||||
Class01 : +int gorilla
|
||||
class Class10~T~ {
|
||||
<<service>>
|
||||
int id
|
||||
size()
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="mermaid">
|
||||
classDiagram
|
||||
Class01~T~ <|-- AveryLongClass : Cool
|
||||
<<interface>> Class01
|
||||
Class03~T~ "0" *-- "0..n" Class04
|
||||
Class05 "1" o-- "many" Class06
|
||||
Class07~T~ .. Class08
|
||||
Class09 "many" --> "1" C2 : Where am i?
|
||||
Class09 "0" --* "1..n" C3
|
||||
Class09 --|> Class07
|
||||
Class07 : equals()
|
||||
Class07 : Object[] elementData
|
||||
Class01 : #size()
|
||||
Class01 : -int chimp
|
||||
Class01 : +int gorilla
|
||||
Class08 <--> C2: Cool label
|
||||
class Class10 {
|
||||
<<service>>
|
||||
int id
|
||||
size()
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="mermaid">
|
||||
stateDiagram
|
||||
State1
|
||||
|
@@ -1,4 +1,4 @@
|
||||
[](https://travis-ci.org/knsv/mermaid)
|
||||
[](https://travis-ci.org/mermaid-js/mermaid)
|
||||
[](https://coveralls.io/github/knsv/mermaid?branch=master)
|
||||
[](https://gitter.im/knsv/mermaid?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
@@ -14,10 +14,12 @@ type, state diagrams.
|
||||
|
||||
## Special note regarding version 8.2
|
||||
|
||||
In version 8.2 a security improvement was introduced. A securityLevel configuration was introduced wich sets the level of trust to be used on the parsed diagrams.
|
||||
In version 8.2 a security improvement was introduced. A securityLevel configuration was introduced which sets the level of trust to be used on the parsed diagrams.
|
||||
|
||||
* **true**: (default) tags in text are encoded, click functionality is disabled
|
||||
* false: tags in text are allowed, click functionality is enabledClosed issues:
|
||||
* false: tags in text are allowed, click functionality is enabled
|
||||
|
||||
Closed issues:
|
||||
|
||||
⚠️ **Note** : This changes the default behaviour of mermaid so that after upgrade to 8.2, if the securityLevel is not configured, tags in flowcharts are encoded as tags and clicking is prohibited.
|
||||
|
||||
@@ -39,7 +41,7 @@ Ever wanted to simplify documentation and avoid heavy tools like Visio when expl
|
||||
|
||||
This is why mermaid was born, a simple markdown-like script language for generating charts from text via javascript.
|
||||
|
||||
**Mermaid was nomiated and won the JS Open Source Awards (2019) in the catory The most existing use of technology!!! Thanks to all involved, people committing pull requests, people answering questions and special thanks to Tyler Long who is helping me maintain the project.**
|
||||
**Mermaid was nominated and won the JS Open Source Awards (2019) in the category "The most exciting use of technology"!!! Thanks to all involved, people committing pull requests, people answering questions and special thanks to Tyler Long who is helping me maintain the project.**
|
||||
|
||||
### Flowchart
|
||||
|
||||
@@ -168,15 +170,15 @@ https://mermaidjs.github.io
|
||||
|
||||
# Request for assistance
|
||||
|
||||
Things are piling up and I have hard time keeping up. To remedy this
|
||||
Things are piling up and I have a hard time keeping up. To remedy this
|
||||
it would be great if we could form a core team of developers to cooperate
|
||||
with the future development mermaid.
|
||||
with the future development of mermaid.
|
||||
|
||||
As part of this team you would get write access to the repository and would
|
||||
represent the project when answering questions and issues.
|
||||
|
||||
Together we could continue the work with things like:
|
||||
* adding more types of diagrams like mindmaps, ert diagrams etc
|
||||
* adding more types of diagrams like mindmaps, ert diagrams, etc.
|
||||
* improving existing diagrams
|
||||
|
||||
Don't hesitate to contact me if you want to get involved.
|
||||
|
@@ -14,8 +14,15 @@
|
||||
- [State Diagram](stateDiagram.md)
|
||||
- [Gantt](gantt.md)
|
||||
- [Pie Chart](pie.md)
|
||||
|
||||
- Guide
|
||||
|
||||
- [Development](development.md)
|
||||
- [mermaidAPI](mermaidAPI.md)
|
||||
- [Changelog](CHANGELOG.md)
|
||||
- [Changelog](CHANGELOG.md)
|
||||
|
||||
- I'm a n00b
|
||||
- [overview](n00b-overview.md)
|
||||
- [Getting started - easier](n00b-gettingStarted.md)
|
||||
- [Diagram syntax intro](n00b-syntaxReference.md)
|
||||
- [Advanced usage](n00b-advanced.md)
|
||||
|
@@ -105,17 +105,10 @@ Naming convention: a class name should be composed of alphanumeric (unicode allo
|
||||
|
||||
UML provides mechanisms to represent class members, such as attributes and methods, and additional information about them.
|
||||
|
||||
#### Visibility
|
||||
To specify the visibility of a class member (i.e. any attribute or method), these notations may be placed before the member's name, but is it optional:
|
||||
Mermaid distinguishes between attributes and functions/methods based on if the **parenthesis** `()` are present or not. The ones with `()` are treated as functions/methods, and others as attributes.
|
||||
|
||||
- `+` Public
|
||||
- `-` Private
|
||||
- `#` Protected
|
||||
- `~` Package
|
||||
|
||||
Mermaid distinguishes between attributes and functions/methods based on if the **parenthesis** `()` are present or not. The one with `()` are treated as functions/methods, and others as attributes.
|
||||
|
||||
There are two ways to define the members of a class, and regardless of the whichever syntax is used to define the members, the output will still be same. The two different ways are :
|
||||
There are two ways to define the members of a class, and regardless of whichever syntax is used to define the members, the output will still be same. The two different ways are :
|
||||
- Associate a member of a class using **:** (colon) followed by member name, useful to define one member at a time. For example:
|
||||
|
||||
```
|
||||
@@ -125,7 +118,7 @@ There are two ways to define the members of a class, and regardless of the which
|
||||
BankAccount : +deposit(amount)
|
||||
BankAccount : +withdrawl(amount)
|
||||
```
|
||||
```mermaid
|
||||
``` mermaid
|
||||
classDiagram
|
||||
class BankAccount
|
||||
BankAccount : +String owner
|
||||
@@ -150,7 +143,22 @@ class BankAccount{
|
||||
+BigDecimal balance
|
||||
+deposit(amount)
|
||||
+withdrawl(amount)
|
||||
}```
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### Visibility
|
||||
To specify the visibility of a class member (i.e. any attribute or method), these notations may be placed before the member's name, but it is optional:
|
||||
|
||||
- `+` Public
|
||||
- `-` Private
|
||||
- `#` Protected
|
||||
- `~` Package
|
||||
|
||||
>_note_ you can also include additional _classifers_ to a method definition by adding the following notations to the end of the method, i.e.: after the `()`:
|
||||
> - `*` Abstract e.g.: `someAbstractMethod()*`
|
||||
> - `$` Static e.g.: `someStaticMethod()$`
|
||||
|
||||
|
||||
## Defining Relationship
|
||||
A relationship is a general term covering the specific types of logical connections found on class and object diagrams.
|
||||
@@ -322,7 +330,20 @@ class Color{
|
||||
}
|
||||
```
|
||||
|
||||
## Comments
|
||||
|
||||
Comments can be entered within a class 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 class diagram syntax
|
||||
|
||||
```
|
||||
classDiagram
|
||||
%% This whole line is a comment classDiagram class Shape <<interface>>
|
||||
class Shape{
|
||||
<<interface>>
|
||||
noOfVertices
|
||||
draw()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Styling
|
||||
|
||||
|
@@ -78,6 +78,17 @@ graph LR
|
||||
id1(This is the text in the box)
|
||||
```
|
||||
|
||||
### A stadium-shaped node
|
||||
|
||||
```
|
||||
graph LR
|
||||
id1([This is the text in the box])
|
||||
```
|
||||
```mermaid
|
||||
graph LR
|
||||
id1([This is the text in the box])
|
||||
```
|
||||
|
||||
### A node in the form of a circle
|
||||
|
||||
```
|
||||
@@ -123,6 +134,28 @@ graph LR
|
||||
id1{{This is the text in the box}}
|
||||
```
|
||||
|
||||
### Parallelogram
|
||||
|
||||
```
|
||||
graph TD
|
||||
id1[/This is the text in the box/]
|
||||
```
|
||||
```mermaid
|
||||
graph TD
|
||||
id1[/This is the text in the box/]
|
||||
```
|
||||
|
||||
### Parallelogram alt
|
||||
|
||||
```
|
||||
graph TD
|
||||
id1[\This is the text in the box\]
|
||||
```
|
||||
```mermaid
|
||||
graph TD
|
||||
id1[\This is the text in the box\]
|
||||
```
|
||||
|
||||
### Trapezoid
|
||||
|
||||
```
|
||||
@@ -402,6 +435,16 @@ Beginners tip, a full example using interactive links in a html context:
|
||||
</body>
|
||||
```
|
||||
|
||||
### Comments
|
||||
|
||||
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
|
||||
%% this is a comment A -- text --> B{node}
|
||||
A -- text --> B -- text2 --> C
|
||||
```
|
||||
|
||||
## Styling and classes
|
||||
|
||||
### Styling links
|
||||
|
@@ -87,6 +87,20 @@ gantt
|
||||
Add another diagram to demo page :48h
|
||||
```
|
||||
|
||||
It is possible to set multiple depenendenies separated by space:
|
||||
```
|
||||
gantt
|
||||
apple :a, 2017-07-20, 1w
|
||||
banana :crit, b, 2017-07-23, 1d
|
||||
cherry :active, c, after b a, 1d
|
||||
```
|
||||
```
|
||||
gantt
|
||||
apple :a, 2017-07-20, 1w
|
||||
banana :crit, b, 2017-07-23, 1d
|
||||
cherry :active, c, after b a, 1d
|
||||
```
|
||||
|
||||
### Title
|
||||
|
||||
Tbd
|
||||
@@ -173,6 +187,23 @@ More info in: http://momentjs.com/docs/#/parsing/string-format/
|
||||
|
||||
More info in: https://github.com/mbostock/d3/wiki/Time-Formatting
|
||||
|
||||
## Comments
|
||||
|
||||
Comments can be entered within a gantt 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
|
||||
|
||||
```
|
||||
gantt
|
||||
title A Gantt Diagram
|
||||
%% this is a comment
|
||||
dateFormat YYYY-MM-DD
|
||||
section Section
|
||||
A task :a1, 2014-01-01, 30d
|
||||
Another task :after a1 , 20d
|
||||
section Another
|
||||
Task in sec :2014-01-12 , 12d
|
||||
another task : 24d
|
||||
|
||||
```
|
||||
|
||||
## Styling
|
||||
|
||||
|
BIN
docs/img/n00b-Confluence1.png
Normal file
BIN
docs/img/n00b-Confluence1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 71 KiB |
BIN
docs/img/n00b-Confluence2.png
Normal file
BIN
docs/img/n00b-Confluence2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
BIN
docs/img/n00b-Confluence3.png
Normal file
BIN
docs/img/n00b-Confluence3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 49 KiB |
BIN
docs/img/n00b-Confluence4.png
Normal file
BIN
docs/img/n00b-Confluence4.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
BIN
docs/img/n00b-firstFlow.png
Normal file
BIN
docs/img/n00b-firstFlow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
BIN
docs/img/n00b-liveEditor.png
Normal file
BIN
docs/img/n00b-liveEditor.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 111 KiB |
@@ -7,8 +7,20 @@
|
||||
<meta name="description" content="Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css">
|
||||
<script src="//cdn.jsdelivr.net/npm/mermaid@8.4.0/dist/mermaid.min.js"></script>
|
||||
<!-- <script src="//localhost:9000/mermaid.js"></script> -->
|
||||
<script src="//cdn.jsdelivr.net/npm/mermaid@8.4.4/dist/mermaid.min.js"></script>
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-153180559-1', 'auto');
|
||||
if(location) {
|
||||
ga('send', 'pageview', location.hash);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.markdown-section {
|
||||
max-width: 1200px;
|
||||
@@ -43,8 +55,18 @@
|
||||
var num = 0;
|
||||
mermaid.initialize({ logLevel:0, startOnLoad: false, themeCSS:'.label { font-family: Source Sans Pro,Helvetica Neue,Arial,sans-serif; }' });
|
||||
|
||||
</script>
|
||||
<script>
|
||||
window.onhashchange = function(a) {
|
||||
//code
|
||||
if(location) {
|
||||
ga('send', 'pageview', location.hash);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
|
||||
<scrpt src="//unpkg.com/docsify/lib/plugins/ga.min.js"></scrpt>
|
||||
</body>
|
||||
</html>
|
||||
<!-- -->
|
@@ -275,7 +275,7 @@ mermaidAPI.initialize({
|
||||
|
||||
<pre>
|
||||
|
||||
<script>
|
||||
<script>
|
||||
var config = {
|
||||
theme:'default',
|
||||
logLevel:'fatal',
|
||||
@@ -317,8 +317,7 @@ mermaidAPI.initialize({
|
||||
}
|
||||
};
|
||||
mermaid.initialize(config);
|
||||
</script>
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
||||
[1]: https://github.com/knsv/mermaid/blob/master/docs/mermaidAPI.md#render
|
||||
|
21
docs/n00b-advanced.md
Normal file
21
docs/n00b-advanced.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Advanced n00b mermaid (Coming soon..)
|
||||
|
||||
## splitting mermaid code from html
|
||||
A more condensed html code can be achieved by embedding the mermaid code in its own .js file, which is referenced like so:
|
||||
|
||||
```
|
||||
stuff stuff
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
The actual mermaid file could for example look like this:
|
||||
|
||||
```
|
||||
mermaid content...
|
||||
```
|
||||
---
|
||||
|
||||
## mermaid configuration options
|
||||
|
||||
...
|
154
docs/n00b-gettingStarted.md
Normal file
154
docs/n00b-gettingStarted.md
Normal file
@@ -0,0 +1,154 @@
|
||||
# A more basic getting started
|
||||
|
||||
Writing mermaid code is simple.
|
||||
|
||||
But how is the code turned into a diagram in a web page? To do this we need a mermaid renderer.
|
||||
|
||||
Thankfully the mermaid renderer is very accessible, in essence it is a javascript.
|
||||
|
||||
The requirement is on the part of the web browser. Modern web browsers, such as Firefox, Chrome and Safari, can render mermaid. But Internet Explorer cannot. The web browser also needs access to the online mermaid renderer which it downloads from https://cdn.jsdelivr.net/npm/mermaid
|
||||
|
||||
For an easy introduction, here follows three practical examples using:
|
||||
1. an online mermaid editor
|
||||
2. a mermaid plugin
|
||||
3. a generic web server of your choosing
|
||||
|
||||
Following either of these examples, you can get started with converting your own mermaid code into web diagrams.
|
||||
|
||||
## the mermaid live editor
|
||||
|
||||
The quickest way to get started with mermaid is to visit [The mermaid live editor](https://mermaidjs.github.io/mermaid-live-editor).
|
||||
|
||||
In the `Code` section one can write or edit raw mermaid code, and instantly `Preview` the rendered result.
|
||||
|
||||
This is a great way to get started.
|
||||
|
||||
It is also the easiest way to develop diagrams, the code of which can be pasted straight into documentation.
|
||||
|
||||

|
||||
|
||||
The `Mermaid configuration` is for controlling mermaid behaviour. An easy introduction to mermaid configuration is found in the [Advanced usage](n00b-advanced.md) section. A complete configuration reference cataloguing default values is found on the [mermaidAPI](mermaidAPI.md) page.
|
||||
|
||||
|
||||
## mermaid using plugins
|
||||
|
||||
Thanks to the growing popularity of mermaid, many plugins already exist which incorporate a mermaid renderer.
|
||||
|
||||
One example is the [Atlassian Confluence mermaid plugin](https://marketplace.atlassian.com/apps/1214124/mermaid-plugin-for-confluence?hosting=server&tab=overview)
|
||||
|
||||
When the mermaid plugin is installed on a Confluence server, one can insert a mermaid object into any Confluence page.
|
||||
|
||||
---
|
||||
|
||||
- In a Confluence page, Add Other macros.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
- Search for mermaid.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
- The mermaid object appears. Paste your mermaid code into it.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
- Save the page and the diagram appears.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## mermaid using any web server (or just a browser)
|
||||
|
||||
This example can be used with any common web server. Apache, IIS, nginx, node express [...], you pick your favourite.
|
||||
|
||||
We do not need to install anything on the server, apart from a normal file of html to be reached by a web browser (such as Firefox, Chrome, Safari, but not Internet Explorer). So if you want to really simplify things when testing this out, don't use a web server at all but just create the file locally and drag it into your browser window. It is the browser which does all the work of rendering mermaid!
|
||||
|
||||
Through the html file, we give the web browser three instructions inside the html code it retrieves:
|
||||
1. a reference for fetching the online mermaid renderer, the renderer is just a javascript.
|
||||
2. the mermaid code we want to diagram.
|
||||
3. the `mermaid.initialize()` command to start the rendering process
|
||||
|
||||
All this is done in the html `<body>` section of the web page.
|
||||
|
||||
This is what needs to go into the html file:
|
||||
|
||||
|
||||
|
||||
1. The reference to the mermaid renderer is done in a `<script src>` tag like so:
|
||||
|
||||
```
|
||||
<body>
|
||||
<script src="https://cdn.jsdelivr.net/npm/mermaid@8.4.0/dist/mermaid.min.js"></script>
|
||||
</body>
|
||||
```
|
||||
|
||||
2. The embedded mermaid code is similarly placed in a `<div>` tag:
|
||||
|
||||
```
|
||||
<body>
|
||||
Here is a mermaid diagram:
|
||||
<div class="mermaid">
|
||||
graph TD
|
||||
A[Client] --> B[Load Balancer]
|
||||
B --> C[Server01]
|
||||
B --> D[Server02]
|
||||
</div>
|
||||
</body>
|
||||
```
|
||||
|
||||
3. When initializing mermaid using `mermaid.initialize()`, mermaid takes all the `<div class="mermaid">` tags it can find in the html body and starts to render them one by one. This is done like so:
|
||||
|
||||
```
|
||||
<body>
|
||||
<script>mermaid.initialize({startOnLoad:true});</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
*Finally*
|
||||
4. Putting the three steps together is as simple as:
|
||||
```
|
||||
<html>
|
||||
<body>
|
||||
<script src="https://cdn.jsdelivr.net/npm/mermaid@8.4.0/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>
|
||||
|
||||
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>
|
||||
```
|
||||
Save this to a html file and fetch it with a browser from the web server (or just drag it into your web browser window) and voila!
|
||||
|
||||
---
|
||||
|
||||
**Three additional comments from Knut Sveidqvist, creator of mermaid:**
|
||||
- In early versions of mermaid, the `<script src>` tag was invoked in the `<head>` part of the web page. Nowdays we can place it directly in `<body>` as seen above. However, older parts of the documentation frequently reflects the previous way which still works.
|
||||
|
||||
- We initialize the mermaid rendering with `mermaid.initialize()` directly in the html code. In principle this could be done through placing `mermaid.initialize()` inside of `mermaid.min.js`. We would then eliminate the need for this explicit line in the html. However, there are use cases where we do want to separate the two steps. Sometimes we want full control over when we start looking for `<div>`tags inside the web page with `mermaid.initialize()`, for example when we think that all `<div>` tags may not have been loaded by the time `mermaid.min.js` runs.
|
||||
|
||||
- In the example above, `mermaid.min.js` is called using an absolute path. Even worse, the example includes the mermaid version number which of course will change as time goes by. However, the example makes it easy to understand what is going on - even though it is perhaps doomed in a way we do not want in a production environment. When going from testing mermaid out to getting serious with it, I would suggest one of the following approaches for calling `mermaid.min.js`:
|
||||
|
||||
1. If you do not enter a specific version, you automatically get the latest one.
|
||||
2. If you really need a specific version, hard code it (this is rare but it happens).
|
||||
3. If you need to know the current mermaid version, replace a mermaid code block with the word `info` and the version will be returned like [this](https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiaW5mb1xuXG4iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ==)
|
||||
|
27
docs/n00b-overview.md
Normal file
27
docs/n00b-overview.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Overview for n00bs
|
||||
|
||||
As a sysadmin I frequently have to document things, including drawing stuff.
|
||||
|
||||
Using mermaid, I can type this as a comment in a script:
|
||||
|
||||
```
|
||||
graph TD
|
||||
A[Client] --> B[Load Balancer]
|
||||
B --> C[Server01]
|
||||
B --> D[Server02]
|
||||
```
|
||||
|
||||
And end up with this in the documentation:
|
||||
|
||||

|
||||
|
||||
Most of the stuff I need to visualize can be scripted in a similar way, with a varitety of different symbols and chart types available. Since the diagram source is text based, it can be part of production scripts (and other pieces of code). So less time needs be spent on documenting as a separate task.
|
||||
|
||||
Comparing with Visio and similar applications, mermaid is a really fast way to create good visualizations. This is especially apparent when editing a complex visualisation, this could take me hours in a desktop application but takes minutes (or even less if generation has been scripted) with mermaid.
|
||||
|
||||
With mermaid I can spend a fraction of the time I normally would spend, and instead automate the diagram generation and end up saving even more time. I love it!
|
||||
|
||||
|
||||
However, a lot of the mermaid documentation is geared to professional frontend developers, presuming a skill set which I simply do not have.
|
||||
|
||||
I needed a really basic instruction. And here it is.
|
11
docs/n00b-syntaxReference.md
Normal file
11
docs/n00b-syntaxReference.md
Normal file
@@ -0,0 +1,11 @@
|
||||
## Diagram syntax reference
|
||||
|
||||
Having already [gotten started](n00b-gettingStarted.md), existing diagram syntax documentation was easy enough to follow even for a n00b like me..
|
||||
|
||||
- [Flowchart](flowchart.md)
|
||||
- [Sequence diagram](sequenceDiagram.md)
|
||||
- [Class Diagram](classDiagram.md)
|
||||
- [State Diagram](stateDiagram.md)
|
||||
- [Gantt](gantt.md)
|
||||
- [Pie Chart](pie.md)
|
||||
|
@@ -271,7 +271,16 @@ sequenceDiagram
|
||||
|
||||
```
|
||||
|
||||
## Comments
|
||||
|
||||
Comments can be entered within a sequence 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 diagram syntax
|
||||
|
||||
```
|
||||
sequenceDiagram
|
||||
Alice->>John: Hello John, how are you?
|
||||
%% this is a comment
|
||||
John-->>Alice: Great!
|
||||
```
|
||||
|
||||
## Styling
|
||||
|
||||
|
@@ -322,6 +322,21 @@ As in plantUml you can specify concurrency using the -- symbol.
|
||||
}
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
```
|
||||
stateDiagram
|
||||
[*] --> Still
|
||||
Still --> [*]
|
||||
%% this is a comment
|
||||
Still --> Moving
|
||||
Moving --> Still %% another comment
|
||||
Moving --> Crash
|
||||
Crash --> [*]
|
||||
```
|
||||
|
||||
## Styling
|
||||
|
||||
Styling of the a state diagram is done by defining a number of css classes. During rendering these classes are extracted from the file located at src/themes/state.scss
|
||||
|
28
package.json
28
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mermaid",
|
||||
"version": "8.4.1",
|
||||
"version": "8.4.4",
|
||||
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
|
||||
"main": "dist/mermaid.core.js",
|
||||
"keywords": [
|
||||
@@ -24,7 +24,7 @@
|
||||
"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",
|
||||
"test": "yarn lint && jest src",
|
||||
"test": "yarn lint && jest src/.*",
|
||||
"test:watch": "jest --watch src",
|
||||
"prepublishOnly": "yarn build && yarn release && yarn test && yarn e2e",
|
||||
"prepush": "yarn test"
|
||||
@@ -49,45 +49,43 @@
|
||||
"@braintree/sanitize-url": "^3.1.0",
|
||||
"crypto-random-string": "^3.0.1",
|
||||
"d3": "^5.7.0",
|
||||
"dagre-d3": "dagrejs/dagre-d3",
|
||||
"dagre": "^0.8.4",
|
||||
"dagre-d3": "^0.6.4",
|
||||
"graphlib": "^2.1.7",
|
||||
"he": "^1.2.0",
|
||||
"lodash": "^4.17.11",
|
||||
"minify": "^4.1.1",
|
||||
"moment-mini": "^2.22.1",
|
||||
"prettier": "^1.18.2",
|
||||
"scope-css": "^1.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"documentation": "^12.0.1",
|
||||
"eslint": "^6.3.0",
|
||||
"eslint-config-prettier": "^6.3.0",
|
||||
"eslint-plugin-prettier": "^3.1.0",
|
||||
"@babel/core": "^7.2.2",
|
||||
"@babel/preset-env": "^7.2.0",
|
||||
"@babel/register": "^7.0.0",
|
||||
"@percy/cypress": "^2.0.1",
|
||||
"babel-core": "7.0.0-bridge.0",
|
||||
"babel-jest": "^23.6.0",
|
||||
"babel-jest": "^24.9.0",
|
||||
"babel-loader": "^8.0.4",
|
||||
"coveralls": "^3.0.2",
|
||||
"css-loader": "^2.0.1",
|
||||
"css-to-string-loader": "^0.1.3",
|
||||
"cypress": "3.4.0",
|
||||
"documentation": "^12.0.1",
|
||||
"eslint": "^6.3.0",
|
||||
"eslint-config-prettier": "^6.3.0",
|
||||
"eslint-plugin-prettier": "^3.1.0",
|
||||
"husky": "^1.2.1",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"jest": "^23.6.0",
|
||||
"jest-environment-puppeteer": "^4.2.0",
|
||||
"jest-image-snapshot": "^2.8.2",
|
||||
"jest-puppeteer": "^4.2.0",
|
||||
"jest": "^24.9.0",
|
||||
"jison": "^0.4.18",
|
||||
"moment": "^2.23.0",
|
||||
"node-sass": "^4.12.0",
|
||||
"prettier": "^1.18.2",
|
||||
"puppeteer": "^1.17.0",
|
||||
"sass-loader": "^7.1.0",
|
||||
"start-server-and-test": "^1.10.0",
|
||||
"webpack": "^4.27.1",
|
||||
"start-server-and-test": "^1.10.6",
|
||||
"terser-webpack-plugin": "^2.2.2",
|
||||
"webpack": "^4.41.2",
|
||||
"webpack-cli": "^3.1.2",
|
||||
"webpack-dev-server": "^3.4.1",
|
||||
"webpack-node-externals": "^1.7.2",
|
||||
|
@@ -3,17 +3,32 @@ import { logger } from '../../logger';
|
||||
let relations = [];
|
||||
let classes = {};
|
||||
|
||||
const splitClassNameAndType = function(id) {
|
||||
let genericType = '';
|
||||
let className = id;
|
||||
|
||||
if (id.indexOf('~') > 0) {
|
||||
let split = id.split('~');
|
||||
className = split[0];
|
||||
genericType = split[1];
|
||||
}
|
||||
|
||||
return { className: className, type: genericType };
|
||||
};
|
||||
|
||||
/**
|
||||
* Function called by parser when a node definition has been found.
|
||||
* @param id
|
||||
* @public
|
||||
*/
|
||||
export const addClass = function(id) {
|
||||
let classId = splitClassNameAndType(id);
|
||||
// Only add class if not exists
|
||||
if (typeof classes[id] !== 'undefined') return;
|
||||
if (typeof classes[classId.className] !== 'undefined') return;
|
||||
|
||||
classes[id] = {
|
||||
id: id,
|
||||
classes[classId.className] = {
|
||||
id: classId.className,
|
||||
type: classId.type,
|
||||
methods: [],
|
||||
members: [],
|
||||
annotations: []
|
||||
@@ -40,6 +55,10 @@ export const addRelation = function(relation) {
|
||||
logger.debug('Adding relation: ' + JSON.stringify(relation));
|
||||
addClass(relation.id1);
|
||||
addClass(relation.id2);
|
||||
|
||||
relation.id1 = splitClassNameAndType(relation.id1).className;
|
||||
relation.id2 = splitClassNameAndType(relation.id2).className;
|
||||
|
||||
relations.push(relation);
|
||||
};
|
||||
|
||||
@@ -51,7 +70,8 @@ export const addRelation = function(relation) {
|
||||
* @public
|
||||
*/
|
||||
export const addAnnotation = function(className, annotation) {
|
||||
classes[className].annotations.push(annotation);
|
||||
const validatedClassName = splitClassNameAndType(className).className;
|
||||
classes[validatedClassName].annotations.push(annotation);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -64,7 +84,9 @@ export const addAnnotation = function(className, annotation) {
|
||||
* @public
|
||||
*/
|
||||
export const addMember = function(className, member) {
|
||||
const theClass = classes[className];
|
||||
const validatedClassName = splitClassNameAndType(className).className;
|
||||
const theClass = classes[validatedClassName];
|
||||
|
||||
if (typeof member === 'string') {
|
||||
// Member can contain white spaces, we trim them out
|
||||
const memberString = member.trim();
|
||||
@@ -72,7 +94,7 @@ export const addMember = function(className, member) {
|
||||
if (memberString.startsWith('<<') && memberString.endsWith('>>')) {
|
||||
// Remove leading and trailing brackets
|
||||
theClass.annotations.push(memberString.substring(2, memberString.length - 2));
|
||||
} else if (memberString.endsWith(')')) {
|
||||
} else if (memberString.indexOf(')') > 0) {
|
||||
theClass.methods.push(memberString);
|
||||
} else if (memberString) {
|
||||
theClass.members.push(memberString);
|
||||
|
@@ -2,13 +2,13 @@
|
||||
import { parser } from './parser/classDiagram';
|
||||
import classDb from './classDb';
|
||||
|
||||
describe('class diagram, ', function() {
|
||||
describe('when parsing an info graph it', function() {
|
||||
beforeEach(function() {
|
||||
describe('class diagram, ', function () {
|
||||
describe('when parsing an info graph it', function () {
|
||||
beforeEach(function () {
|
||||
parser.yy = classDb;
|
||||
});
|
||||
|
||||
it('should handle relation definitions', function() {
|
||||
it('should handle relation definitions', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'Class01 <|-- Class02\n' +
|
||||
@@ -19,7 +19,8 @@ describe('class diagram, ', function() {
|
||||
|
||||
parser.parse(str);
|
||||
});
|
||||
it('should handle relation definition of different types and directions', function() {
|
||||
|
||||
it('should handle relation definition of different types and directions', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'Class11 <|.. Class12\n' +
|
||||
@@ -31,7 +32,7 @@ describe('class diagram, ', function() {
|
||||
parser.parse(str);
|
||||
});
|
||||
|
||||
it('should handle cardinality and labels', function() {
|
||||
it('should handle cardinality and labels', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'Class01 "1" *-- "many" Class02 : contains\n' +
|
||||
@@ -40,6 +41,48 @@ describe('class diagram, ', function() {
|
||||
|
||||
parser.parse(str);
|
||||
});
|
||||
|
||||
it('should handle visibility for methods and members', function() {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class TestClass\n' +
|
||||
'TestClass : -int privateMember\n' +
|
||||
'TestClass : +int publicMember\n' +
|
||||
'TestClass : #int protectedMember\n' +
|
||||
'TestClass : -privateMethod()\n' +
|
||||
'TestClass : +publicMethod()\n' +
|
||||
'TestClass : #protectedMethod()\n';
|
||||
|
||||
parser.parse(str);
|
||||
});
|
||||
|
||||
it('should handle generic class', function() {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Car~T~\n' +
|
||||
'Driver -- Car : drives >\n' +
|
||||
'Car *-- Wheel : have 4 >\n' +
|
||||
'Car -- Person : < owns';
|
||||
|
||||
parser.parse(str);
|
||||
});
|
||||
|
||||
it('should handle generic class with brackets', function() {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Dummy_Class~T~ {\n' +
|
||||
'String data\n' +
|
||||
' void methods()\n' +
|
||||
'}\n' +
|
||||
'\n' +
|
||||
'class Flight {\n' +
|
||||
' flightNumber : Integer\n' +
|
||||
' departureTime : Date\n' +
|
||||
'}';
|
||||
|
||||
parser.parse(str);
|
||||
});
|
||||
|
||||
it('should handle class definitions', function() {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
@@ -51,7 +94,7 @@ describe('class diagram, ', function() {
|
||||
parser.parse(str);
|
||||
});
|
||||
|
||||
it('should handle method statements', function() {
|
||||
it('should handle method statements', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'Object <|-- ArrayList\n' +
|
||||
@@ -61,7 +104,8 @@ describe('class diagram, ', function() {
|
||||
|
||||
parser.parse(str);
|
||||
});
|
||||
it('should handle parsing of method statements grouped by brackets', function() {
|
||||
|
||||
it('should handle parsing of method statements grouped by brackets', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Dummy_Class {\n' +
|
||||
@@ -77,7 +121,7 @@ describe('class diagram, ', function() {
|
||||
parser.parse(str);
|
||||
});
|
||||
|
||||
it('should handle parsing of separators', function() {
|
||||
it('should handle parsing of separators', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Foo1 {\n' +
|
||||
@@ -109,14 +153,111 @@ describe('class diagram, ', function() {
|
||||
|
||||
parser.parse(str);
|
||||
});
|
||||
|
||||
it('should handle a comment', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1 {\n' +
|
||||
'%% Comment\n' +
|
||||
'int : test\n' +
|
||||
'string : foo\n' +
|
||||
'test()\n' +
|
||||
'foo()\n' +
|
||||
'}';
|
||||
|
||||
parser.parse(str);
|
||||
});
|
||||
|
||||
it('should handle comments at the start', function () {
|
||||
const str =
|
||||
'%% Comment\n' +
|
||||
'classDiagram\n' +
|
||||
'class Class1 {\n' +
|
||||
'int : test\n' +
|
||||
'string : foo\n' +
|
||||
'test()\n' +
|
||||
'foo()\n' +
|
||||
'}';
|
||||
parser.parse(str);
|
||||
});
|
||||
|
||||
it('should handle comments at the end', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1 {\n' +
|
||||
'int : test\n' +
|
||||
'string : foo\n' +
|
||||
'test()\n' +
|
||||
'foo()\n' +
|
||||
'\n}' +
|
||||
'%% Comment\n';
|
||||
|
||||
parser.parse(str);
|
||||
});
|
||||
|
||||
it('should handle comments at the end no trailing newline', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1 {\n' +
|
||||
'int : test\n' +
|
||||
'string : foo\n' +
|
||||
'test()\n' +
|
||||
'foo()\n' +
|
||||
'}\n' +
|
||||
'%% Comment';
|
||||
|
||||
parser.parse(str);
|
||||
});
|
||||
|
||||
it('should handle a comment with multiple line feeds', function () {
|
||||
const str =
|
||||
'classDiagram\n\n\n' +
|
||||
'%% Comment\n\n' +
|
||||
'class Class1 {\n' +
|
||||
'int : test\n' +
|
||||
'string : foo\n' +
|
||||
'test()\n' +
|
||||
'foo()\n' +
|
||||
'}';
|
||||
|
||||
parser.parse(str);
|
||||
});
|
||||
|
||||
it('should handle a comment with mermaid class diagram code in them', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'%% Comment Class01 <|-- Class02\n' +
|
||||
'class Class1 {\n' +
|
||||
'int : test\n' +
|
||||
'string : foo\n' +
|
||||
'test()\n' +
|
||||
'foo()\n' +
|
||||
'}';
|
||||
|
||||
parser.parse(str);
|
||||
});
|
||||
|
||||
it('should handle a comment inside brackets', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1 {\n' +
|
||||
'%% Comment Class01 <|-- Class02\n' +
|
||||
'int : test\n' +
|
||||
'string : foo\n' +
|
||||
'test()\n' +
|
||||
'foo()\n' +
|
||||
'}';
|
||||
|
||||
parser.parse(str);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when fetching data from an classDiagram graph it', function() {
|
||||
beforeEach(function() {
|
||||
describe('when fetching data from a classDiagram graph it', function () {
|
||||
beforeEach(function () {
|
||||
parser.yy = classDb;
|
||||
parser.yy.clear();
|
||||
});
|
||||
it('should handle relation definitions EXTENSION', function() {
|
||||
it('should handle relation definitions EXTENSION', function () {
|
||||
const str = 'classDiagram\n' + 'Class01 <|-- Class02';
|
||||
|
||||
parser.parse(str);
|
||||
@@ -129,7 +270,8 @@ describe('class diagram, ', function() {
|
||||
expect(relations[0].relation.type2).toBe('none');
|
||||
expect(relations[0].relation.lineType).toBe(classDb.lineType.LINE);
|
||||
});
|
||||
it('should handle relation definitions AGGREGATION and dotted line', function() {
|
||||
|
||||
it('should handle relation definitions AGGREGATION and dotted line', function () {
|
||||
const str = 'classDiagram\n' + 'Class01 o.. Class02';
|
||||
|
||||
parser.parse(str);
|
||||
@@ -142,7 +284,8 @@ describe('class diagram, ', function() {
|
||||
expect(relations[0].relation.type2).toBe('none');
|
||||
expect(relations[0].relation.lineType).toBe(classDb.lineType.DOTTED_LINE);
|
||||
});
|
||||
it('should handle relation definitions COMPOSITION on both sides', function() {
|
||||
|
||||
it('should handle relation definitions COMPOSITION on both sides', function () {
|
||||
const str = 'classDiagram\n' + 'Class01 *--* Class02';
|
||||
|
||||
parser.parse(str);
|
||||
@@ -155,7 +298,8 @@ describe('class diagram, ', function() {
|
||||
expect(relations[0].relation.type2).toBe(classDb.relationType.COMPOSITION);
|
||||
expect(relations[0].relation.lineType).toBe(classDb.lineType.LINE);
|
||||
});
|
||||
it('should handle relation definitions no types', function() {
|
||||
|
||||
it('should handle relation definitions no types', function () {
|
||||
const str = 'classDiagram\n' + 'Class01 -- Class02';
|
||||
|
||||
parser.parse(str);
|
||||
@@ -168,7 +312,8 @@ describe('class diagram, ', function() {
|
||||
expect(relations[0].relation.type2).toBe('none');
|
||||
expect(relations[0].relation.lineType).toBe(classDb.lineType.LINE);
|
||||
});
|
||||
it('should handle relation definitions with type only on right side', function() {
|
||||
|
||||
it('should handle relation definitions with type only on right side', function () {
|
||||
const str = 'classDiagram\n' + 'Class01 --|> Class02';
|
||||
|
||||
parser.parse(str);
|
||||
@@ -182,7 +327,7 @@ describe('class diagram, ', function() {
|
||||
expect(relations[0].relation.lineType).toBe(classDb.lineType.LINE);
|
||||
});
|
||||
|
||||
it('should handle multiple classes and relation definitions', function() {
|
||||
it('should handle multiple classes and relation definitions', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'Class01 <|-- Class02\n' +
|
||||
@@ -208,7 +353,22 @@ describe('class diagram, ', function() {
|
||||
expect(relations[3].relation.lineType).toBe(classDb.lineType.DOTTED_LINE);
|
||||
});
|
||||
|
||||
it('should handle class annotations', function() {
|
||||
it('should handle generic class with relation definitions', function () {
|
||||
const str = 'classDiagram\n' + 'Class01~T~ <|-- Class02';
|
||||
|
||||
parser.parse(str);
|
||||
|
||||
const relations = parser.yy.getRelations();
|
||||
|
||||
expect(parser.yy.getClass('Class01').id).toBe('Class01');
|
||||
expect(parser.yy.getClass('Class01').type).toBe('T');
|
||||
expect(parser.yy.getClass('Class02').id).toBe('Class02');
|
||||
expect(relations[0].relation.type1).toBe(classDb.relationType.EXTENSION);
|
||||
expect(relations[0].relation.type2).toBe('none');
|
||||
expect(relations[0].relation.lineType).toBe(classDb.lineType.LINE);
|
||||
});
|
||||
|
||||
it('should handle class annotations', function () {
|
||||
const str = 'classDiagram\n' + 'class Class1\n' + '<<interface>> Class1';
|
||||
parser.parse(str);
|
||||
|
||||
@@ -219,7 +379,7 @@ describe('class diagram, ', function() {
|
||||
expect(testClass.annotations[0]).toBe('interface');
|
||||
});
|
||||
|
||||
it('should handle class annotations with members and methods', function() {
|
||||
it('should handle class annotations with members and methods', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1\n' +
|
||||
@@ -235,7 +395,7 @@ describe('class diagram, ', function() {
|
||||
expect(testClass.annotations[0]).toBe('interface');
|
||||
});
|
||||
|
||||
it('should handle class annotations in brackets', function() {
|
||||
it('should handle class annotations in brackets', function () {
|
||||
const str = 'classDiagram\n' + 'class Class1 {\n' + '<<interface>>\n' + '}';
|
||||
parser.parse(str);
|
||||
|
||||
@@ -246,7 +406,7 @@ describe('class diagram, ', function() {
|
||||
expect(testClass.annotations[0]).toBe('interface');
|
||||
});
|
||||
|
||||
it('should handle class annotations in brackets with members and methods', function() {
|
||||
it('should handle class annotations in brackets with members and methods', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1 {\n' +
|
||||
@@ -263,7 +423,7 @@ describe('class diagram, ', function() {
|
||||
expect(testClass.annotations[0]).toBe('interface');
|
||||
});
|
||||
|
||||
it('should add bracket members in right order', function() {
|
||||
it('should add bracket members in right order', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1 {\n' +
|
||||
@@ -282,5 +442,27 @@ describe('class diagram, ', function() {
|
||||
expect(testClass.methods[0]).toBe('test()');
|
||||
expect(testClass.methods[1]).toBe('foo()');
|
||||
});
|
||||
|
||||
it('should handle abstract methods', function () {
|
||||
const str = 'classDiagram\n' + 'class Class1\n' + 'Class1 : someMethod()*';
|
||||
parser.parse(str);
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.annotations.length).toBe(0);
|
||||
expect(testClass.members.length).toBe(0);
|
||||
expect(testClass.methods.length).toBe(1);
|
||||
expect(testClass.methods[0]).toBe('someMethod()*');
|
||||
});
|
||||
|
||||
it('should handle static methods', function () {
|
||||
const str = 'classDiagram\n' + 'class Class1\n' + 'Class1 : someMethod()$';
|
||||
parser.parse(str);
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.annotations.length).toBe(0);
|
||||
expect(testClass.members.length).toBe(0);
|
||||
expect(testClass.methods.length).toBe(1);
|
||||
expect(testClass.methods[0]).toBe('someMethod()$');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -8,7 +8,7 @@ import { parser } from './parser/classDiagram';
|
||||
|
||||
parser.yy = classDb;
|
||||
|
||||
const idCache = {};
|
||||
let idCache = {};
|
||||
|
||||
let classCnt = 0;
|
||||
const conf = {
|
||||
@@ -136,7 +136,6 @@ const insertMarkers = function(elem) {
|
||||
};
|
||||
|
||||
let edgeCount = 0;
|
||||
let total = 0;
|
||||
const drawEdge = function(elem, path, relation) {
|
||||
const getRelationType = function(type) {
|
||||
switch (type) {
|
||||
@@ -282,16 +281,40 @@ const drawClass = function(elem, classDef) {
|
||||
logger.info('Rendering class ' + classDef);
|
||||
|
||||
const addTspan = function(textEl, txt, isFirst) {
|
||||
let displayText = txt;
|
||||
let cssStyle = '';
|
||||
let methodEnd = txt.indexOf(')') + 1;
|
||||
|
||||
if (methodEnd > 1 && methodEnd <= txt.length) {
|
||||
let classifier = txt.substring(methodEnd);
|
||||
|
||||
switch (classifier) {
|
||||
case '*':
|
||||
cssStyle = 'font-style:italic;';
|
||||
break;
|
||||
case '$':
|
||||
cssStyle = 'text-decoration:underline;';
|
||||
break;
|
||||
}
|
||||
|
||||
displayText = txt.substring(0, methodEnd);
|
||||
}
|
||||
|
||||
const tSpan = textEl
|
||||
.append('tspan')
|
||||
.attr('x', conf.padding)
|
||||
.text(txt);
|
||||
.text(displayText);
|
||||
|
||||
if (cssStyle !== '') {
|
||||
tSpan.attr('style', cssStyle);
|
||||
}
|
||||
|
||||
if (!isFirst) {
|
||||
tSpan.attr('dy', conf.textHeight);
|
||||
}
|
||||
};
|
||||
|
||||
const id = 'classId' + (classCnt % total);
|
||||
const id = 'classId' + classCnt;
|
||||
const classInfo = {
|
||||
id: id,
|
||||
label: classDef.id,
|
||||
@@ -319,10 +342,16 @@ const drawClass = function(elem, classDef) {
|
||||
isFirst = false;
|
||||
});
|
||||
|
||||
let classTitleString = classDef.id;
|
||||
|
||||
if (classDef.type !== undefined && classDef.type !== '') {
|
||||
classTitleString += '<' + classDef.type + '>';
|
||||
}
|
||||
|
||||
// add class title
|
||||
const classTitle = title
|
||||
.append('tspan')
|
||||
.text(classDef.id)
|
||||
.text(classTitleString)
|
||||
.attr('class', 'title');
|
||||
|
||||
// If class has annotations the title needs to have an offset of the text height
|
||||
@@ -411,6 +440,7 @@ export const setConf = function(cnf) {
|
||||
* @param id
|
||||
*/
|
||||
export const draw = function(text, id) {
|
||||
idCache = {};
|
||||
parser.yy.clear();
|
||||
parser.parse(text);
|
||||
|
||||
@@ -437,7 +467,6 @@ export const draw = function(text, id) {
|
||||
|
||||
const classes = classDb.getClasses();
|
||||
const keys = Object.keys(classes);
|
||||
total = keys.length;
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const classDef = classes[keys[i]];
|
||||
const node = drawClass(diagram, classDef);
|
||||
|
@@ -6,10 +6,10 @@
|
||||
|
||||
/* lexical grammar */
|
||||
%lex
|
||||
%x string struct
|
||||
%x string generic struct
|
||||
|
||||
%%
|
||||
\%\%[^\n]* /* do nothing */
|
||||
\%\%[^\n]*\n* /* do nothing */
|
||||
\n+ return 'NEWLINE';
|
||||
\s+ /* skip whitespace */
|
||||
"classDiagram" return 'CLASS_DIAGRAM';
|
||||
@@ -23,6 +23,9 @@
|
||||
"class" return 'CLASS';
|
||||
"<<" return 'ANNOTATION_START';
|
||||
">>" return 'ANNOTATION_END';
|
||||
[~] this.begin("generic");
|
||||
<generic>[~] this.popState();
|
||||
<generic>[^~]* return "GENERICTYPE";
|
||||
["] this.begin("string");
|
||||
<string>["] this.popState();
|
||||
<string>[^"]* return "STR";
|
||||
@@ -36,7 +39,7 @@
|
||||
\s*o return 'AGGREGATION';
|
||||
\-\- return 'LINE';
|
||||
\.\. return 'DOTTED_LINE';
|
||||
":"[^#\n;]+ return 'LABEL';
|
||||
":"[^\n;]+ return 'LABEL';
|
||||
\- return 'MINUS';
|
||||
"." return 'DOT';
|
||||
\+ return 'PLUS';
|
||||
@@ -136,6 +139,8 @@ statements
|
||||
className
|
||||
: alphaNumToken className { $$=$1+$2; }
|
||||
| alphaNumToken { $$=$1; }
|
||||
| alphaNumToken GENERICTYPE className { $$=$1+'~'+$2+$3; }
|
||||
| alphaNumToken GENERICTYPE { $$=$1+'~'+$2; }
|
||||
;
|
||||
|
||||
statement
|
||||
|
@@ -135,9 +135,29 @@ function rect_right_inv_arrow(parent, bbox, node) {
|
||||
return shapeSvg;
|
||||
}
|
||||
|
||||
function stadium(parent, bbox, node) {
|
||||
const h = bbox.height;
|
||||
const w = bbox.width + h / 4;
|
||||
|
||||
const shapeSvg = parent
|
||||
.insert('rect', ':first-child')
|
||||
.attr('rx', h / 2)
|
||||
.attr('ry', h / 2)
|
||||
.attr('x', -w / 2)
|
||||
.attr('y', -h / 2)
|
||||
.attr('width', w)
|
||||
.attr('height', h);
|
||||
|
||||
node.intersect = function(point) {
|
||||
return dagreD3.intersect.rect(node, point);
|
||||
};
|
||||
return shapeSvg;
|
||||
}
|
||||
|
||||
export function addToRender(render) {
|
||||
render.shapes().question = question;
|
||||
render.shapes().hexagon = hexagon;
|
||||
render.shapes().stadium = stadium;
|
||||
|
||||
// Add custom shape for box with inverted arrow on left side
|
||||
render.shapes().rect_left_inv_arrow = rect_left_inv_arrow;
|
||||
|
@@ -1,6 +1,29 @@
|
||||
import { addToRender } from './flowChartShapes';
|
||||
|
||||
describe('flowchart shapes', function() {
|
||||
// rect-based shapes
|
||||
[
|
||||
['stadium', useWidth, useHeight]
|
||||
].forEach(function([shapeType, getW, getH]) {
|
||||
it(`should add a ${shapeType} shape that renders a properly positioned rect element`, function() {
|
||||
const mockRender = MockRender();
|
||||
const mockSvg = MockSvg();
|
||||
addToRender(mockRender);
|
||||
|
||||
[[100, 100], [123, 45], [71, 300]].forEach(function([width, height]) {
|
||||
const shape = mockRender.shapes()[shapeType](mockSvg, { width, height }, {});
|
||||
const w = width + height / 4;
|
||||
const h = height;
|
||||
const dx = -getW(w, h) / 2;
|
||||
const dy = -getH(w, h) / 2;
|
||||
expect(shape.__tag).toEqual('rect');
|
||||
expect(shape.__attrs).toHaveProperty('x', dx);
|
||||
expect(shape.__attrs).toHaveProperty('y', dy);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// polygon-based shapes
|
||||
[
|
||||
[
|
||||
'question',
|
||||
|
@@ -4,6 +4,9 @@ import { logger } from '../../logger';
|
||||
import utils from '../../utils';
|
||||
import { getConfig } from '../../config';
|
||||
|
||||
// const MERMAID_DOM_ID_PREFIX = 'mermaid-dom-id-';
|
||||
const MERMAID_DOM_ID_PREFIX = '';
|
||||
|
||||
const config = getConfig();
|
||||
let vertices = {};
|
||||
let edges = [];
|
||||
@@ -19,7 +22,13 @@ let funs = [];
|
||||
|
||||
const sanitize = text => {
|
||||
let txt = text;
|
||||
if (config.securityLevel !== 'loose') {
|
||||
let htmlLabels = true;
|
||||
if (
|
||||
config.flowchart &&
|
||||
(config.flowchart.htmlLabels === false || config.flowchart.htmlLabels === 'false')
|
||||
)
|
||||
htmlLabels = false;
|
||||
if (config.securityLevel !== 'loose' && htmlLabels) { // eslint-disable-line
|
||||
txt = txt.replace(/<br>/g, '#br#');
|
||||
txt = txt.replace(/<br\S*?\/>/g, '#br#');
|
||||
txt = txt.replace(/</g, '<').replace(/>/g, '>');
|
||||
@@ -48,7 +57,7 @@ export const addVertex = function(_id, text, type, style, classes) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (id[0].match(/\d/)) id = 's' + id;
|
||||
if (id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id;
|
||||
|
||||
if (typeof vertices[id] === 'undefined') {
|
||||
vertices[id] = { id: id, styles: [], classes: [] };
|
||||
@@ -96,8 +105,8 @@ export const addVertex = function(_id, text, type, style, classes) {
|
||||
export const addLink = function(_start, _end, type, linktext) {
|
||||
let start = _start;
|
||||
let end = _end;
|
||||
if (start[0].match(/\d/)) start = 's' + start;
|
||||
if (end[0].match(/\d/)) end = 's' + end;
|
||||
if (start[0].match(/\d/)) start = MERMAID_DOM_ID_PREFIX + start;
|
||||
if (end[0].match(/\d/)) end = MERMAID_DOM_ID_PREFIX + end;
|
||||
logger.info('Got edge...', start, end);
|
||||
|
||||
const edge = { start: start, end: end, type: undefined, text: '' };
|
||||
@@ -194,7 +203,7 @@ export const setDirection = function(dir) {
|
||||
export const setClass = function(ids, className) {
|
||||
ids.split(',').forEach(function(_id) {
|
||||
let id = _id;
|
||||
if (_id[0].match(/\d/)) id = 's' + id;
|
||||
if (_id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id;
|
||||
if (typeof vertices[id] !== 'undefined') {
|
||||
vertices[id].classes.push(className);
|
||||
}
|
||||
@@ -215,7 +224,7 @@ const setTooltip = function(ids, tooltip) {
|
||||
|
||||
const setClickFun = function(_id, functionName) {
|
||||
let id = _id;
|
||||
if (_id[0].match(/\d/)) id = 's' + id;
|
||||
if (_id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id;
|
||||
if (config.securityLevel !== 'loose') {
|
||||
return;
|
||||
}
|
||||
@@ -247,7 +256,7 @@ const setClickFun = function(_id, functionName) {
|
||||
export const setLink = function(ids, linkStr, tooltip) {
|
||||
ids.split(',').forEach(function(_id) {
|
||||
let id = _id;
|
||||
if (_id[0].match(/\d/)) id = 's' + id;
|
||||
if (_id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id;
|
||||
if (typeof vertices[id] !== 'undefined') {
|
||||
if (config.securityLevel !== 'loose') {
|
||||
vertices[id].link = sanitizeUrl(linkStr); // .replace(/javascript:.*/g, '')
|
||||
@@ -406,11 +415,11 @@ export const addSubGraph = function(_id, list, _title) {
|
||||
|
||||
nodeList = uniq(nodeList.concat.apply(nodeList, list));
|
||||
for (let i = 0; i < nodeList.length; i++) {
|
||||
if (nodeList[i][0].match(/\d/)) nodeList[i] = 's' + nodeList[i];
|
||||
if (nodeList[i][0].match(/\d/)) nodeList[i] = MERMAID_DOM_ID_PREFIX + nodeList[i];
|
||||
}
|
||||
|
||||
id = id || 'subGraph' + subCount;
|
||||
if (id[0].match(/\d/)) id = 's' + id;
|
||||
if (id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id;
|
||||
title = title || '';
|
||||
title = sanitize(title);
|
||||
subCount = subCount + 1;
|
||||
|
@@ -8,7 +8,6 @@ import { getConfig } from '../../config';
|
||||
const newDagreD3 = true;
|
||||
import dagreD3 from 'dagre-d3';
|
||||
// const newDagreD3 = false;
|
||||
// import dagreD3 from '../../../../dagre-d3-renderer/dist/dagre-d3.core.js';
|
||||
|
||||
import addHtmlLabel from 'dagre-d3/lib/label/add-html-label.js';
|
||||
import { logger } from '../../logger';
|
||||
@@ -155,6 +154,9 @@ export const addVertices = function(vert, g, svgId) {
|
||||
case 'ellipse':
|
||||
_shape = 'ellipse';
|
||||
break;
|
||||
case 'stadium':
|
||||
_shape = 'stadium';
|
||||
break;
|
||||
case 'group':
|
||||
_shape = 'rect';
|
||||
break;
|
||||
@@ -214,10 +216,10 @@ export const addEdges = function(edges, g) {
|
||||
}
|
||||
break;
|
||||
case 'dotted':
|
||||
style = 'stroke: #333; fill:none;stroke-width:2px;stroke-dasharray:3;';
|
||||
style = 'fill:none;stroke-width:2px;stroke-dasharray:3;';
|
||||
break;
|
||||
case 'thick':
|
||||
style = 'stroke: #333; stroke-width: 3.5px;fill:none';
|
||||
style = ' stroke-width: 3.5px;fill:none';
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -237,18 +239,18 @@ export const addEdges = function(edges, g) {
|
||||
}
|
||||
} else {
|
||||
edgeData.arrowheadStyle = 'fill: #333';
|
||||
if (typeof edge.style === 'undefined') {
|
||||
edgeData.labelpos = 'c';
|
||||
if (getConfig().flowchart.htmlLabels) {
|
||||
edgeData.labelType = 'html';
|
||||
edgeData.label = '<span class="edgeLabel">' + edge.text + '</span>';
|
||||
} else {
|
||||
edgeData.labelType = 'text';
|
||||
edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none';
|
||||
edgeData.label = edge.text.replace(/<br>/g, '\n');
|
||||
}
|
||||
edgeData.labelpos = 'c';
|
||||
|
||||
if (getConfig().flowchart.htmlLabels) {
|
||||
edgeData.labelType = 'html';
|
||||
edgeData.label = '<span class="edgeLabel">' + edge.text + '</span>';
|
||||
} else {
|
||||
edgeData.label = edge.text.replace(/<br>/g, '\n');
|
||||
edgeData.labelType = 'text';
|
||||
edgeData.label = edge.text.replace(/<br ?\/?>/g, '\n');
|
||||
|
||||
if (typeof edge.style === 'undefined') {
|
||||
edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none';
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add the edge to the graph
|
||||
@@ -460,8 +462,8 @@ export const draw = function(text, id) {
|
||||
subG = subGraphs[i];
|
||||
|
||||
if (subG.title !== 'undefined') {
|
||||
const clusterRects = document.querySelectorAll('#' + id + ' #' + subG.id + ' rect');
|
||||
const clusterEl = document.querySelectorAll('#' + id + ' #' + subG.id);
|
||||
const clusterRects = document.querySelectorAll('#' + id + ' [id="' + subG.id + '"] rect');
|
||||
const clusterEl = document.querySelectorAll('#' + id + ' [id="' + subG.id + '"]');
|
||||
|
||||
const xPos = clusterRects[0].x.baseVal.value;
|
||||
const yPos = clusterRects[0].y.baseVal.value;
|
||||
@@ -475,7 +477,7 @@ export const draw = function(text, id) {
|
||||
|
||||
// Add label rects for non html labels
|
||||
if (!conf.htmlLabels) {
|
||||
const labels = document.querySelectorAll('#' + id + ' .edgeLabel .label');
|
||||
const labels = document.querySelectorAll('[id="' + id + '"] .edgeLabel .label');
|
||||
for (let k = 0; k < labels.length; k++) {
|
||||
const label = labels[k];
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { addVertices } from './flowRenderer';
|
||||
import { addVertices, addEdges } from './flowRenderer';
|
||||
import { setConfig } from '../../config';
|
||||
|
||||
setConfig({
|
||||
@@ -22,6 +22,7 @@ describe('the flowchart renderer', function() {
|
||||
['odd_right', 'rect_left_inv_arrow'],
|
||||
['circle', 'circle'],
|
||||
['ellipse', 'ellipse'],
|
||||
['stadium', 'stadium'],
|
||||
['group', 'rect']
|
||||
].forEach(function([type, expectedShape, expectedRadios = 0]) {
|
||||
it(`should add the correct shaped node to the graph for vertex type ${type}`, function() {
|
||||
@@ -93,4 +94,32 @@ describe('the flowchart renderer', function() {
|
||||
expect(addedNodes[0][1]).toHaveProperty('labelStyle', expectedLabelStyle);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when adding edges to a graph', function() {
|
||||
it('should handle multiline texts and set centered label position', function() {
|
||||
const addedEdges = [];
|
||||
const mockG = {
|
||||
setEdge: function(s, e, data, c) {
|
||||
addedEdges.push(data);
|
||||
}
|
||||
};
|
||||
addEdges(
|
||||
[
|
||||
{ text: 'Multi<br>Line' },
|
||||
{ text: 'Multi<br/>Line' },
|
||||
{ text: 'Multi<br />Line' },
|
||||
{ style: ['stroke:DarkGray', 'stroke-width:2px'], text: 'Multi<br>Line' },
|
||||
{ style: ['stroke:DarkGray', 'stroke-width:2px'], text: 'Multi<br/>Line' },
|
||||
{ style: ['stroke:DarkGray', 'stroke-width:2px'], text: 'Multi<br />Line' }
|
||||
],
|
||||
mockG,
|
||||
'svg-id'
|
||||
);
|
||||
|
||||
addedEdges.forEach(function(edge) {
|
||||
expect(edge).toHaveProperty('label', 'Multi\nLine');
|
||||
expect(edge).toHaveProperty('labelpos', 'c');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -12,8 +12,8 @@ describe('[Comments] when parsing', () => {
|
||||
flow.parser.yy.clear();
|
||||
});
|
||||
|
||||
it('should handle a comments', function() {
|
||||
const res = flow.parser.parse('graph TD;\n%% CComment\n A-->B;');
|
||||
it('should handle comments', function() {
|
||||
const res = flow.parser.parse('graph TD;\n%% Comment\n A-->B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
@@ -27,7 +27,7 @@ describe('[Comments] when parsing', () => {
|
||||
expect(edges[0].text).toBe('');
|
||||
});
|
||||
|
||||
it('should handle comments a at the start', function() {
|
||||
it('should handle comments at the start', function() {
|
||||
const res = flow.parser.parse('%% Comment\ngraph TD;\n A-->B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
@@ -43,7 +43,7 @@ describe('[Comments] when parsing', () => {
|
||||
});
|
||||
|
||||
it('should handle comments at the end', function() {
|
||||
const res = flow.parser.parse('graph TD;\n A-->B\n %% Comment at the find\n');
|
||||
const res = flow.parser.parse('graph TD;\n A-->B\n %% Comment at the end\n');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
@@ -117,7 +117,7 @@ describe('[Comments] when parsing', () => {
|
||||
expect(edges[0].text).toBe('');
|
||||
});
|
||||
|
||||
it('should handle a comments with blank rows in-between', function() {
|
||||
it('should handle a comment with blank rows in-between', function() {
|
||||
const res = flow.parser.parse('graph TD;\n\n\n %% Comment\n A-->B;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
@@ -132,7 +132,7 @@ describe('[Comments] when parsing', () => {
|
||||
expect(edges[0].text).toBe('');
|
||||
});
|
||||
|
||||
it('should handle a comments mermaid flowchart code in them', function() {
|
||||
it('should handle a comment with mermaid flowchart code in them', function() {
|
||||
const res = flow.parser.parse(
|
||||
'graph TD;\n\n\n %% Test od>Odd shape]-->|Two line<br>edge comment|ro;\n A-->B;'
|
||||
);
|
||||
|
@@ -168,7 +168,7 @@ describe('[Singlenodes] when parsing', () => {
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert['s1'].text).toBe('1');
|
||||
expect(vert['1'].text).toBe('1');
|
||||
});
|
||||
|
||||
it('should handle a single node with a single digit in a subgraph', function() {
|
||||
@@ -180,7 +180,7 @@ describe('[Singlenodes] when parsing', () => {
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert['s1'].text).toBe('1');
|
||||
expect(vert['1'].text).toBe('1');
|
||||
});
|
||||
|
||||
it('should handle a single node with alphanumerics starting on a num', function() {
|
||||
@@ -191,7 +191,7 @@ describe('[Singlenodes] when parsing', () => {
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
||||
expect(edges.length).toBe(0);
|
||||
expect(vert['s1id'].styles.length).toBe(0);
|
||||
expect(vert['1id'].styles.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle a single node with alphanumerics containing a minus sign', function() {
|
||||
|
@@ -9,7 +9,7 @@
|
||||
%x string
|
||||
%x dir
|
||||
%%
|
||||
\%\%[^\n]* /* do nothing */
|
||||
\%\%[^\n]*\n* /* do nothing */
|
||||
["] this.begin("string");
|
||||
<string>["] this.popState();
|
||||
<string>[^"]* return "STR";
|
||||
@@ -82,6 +82,8 @@
|
||||
\s*\=\=\s* return '==';
|
||||
"(-" return '(-';
|
||||
"-)" return '-)';
|
||||
"([" return 'STADIUMSTART';
|
||||
"])" return 'STADIUMEND';
|
||||
\- return 'MINUS';
|
||||
"." return 'DOT';
|
||||
[\_] return 'UNDERSCORE';
|
||||
@@ -96,8 +98,8 @@
|
||||
[A-Za-z]+ return 'ALPHA';
|
||||
"\\]" return 'TRAPEND';
|
||||
"[/" return 'TRAPSTART';
|
||||
"/]" return 'INVTRAPEND';
|
||||
"[\\" return 'INVTRAPSTART';
|
||||
"/]" return 'INVTRAPEND';
|
||||
"[\\" return 'INVTRAPSTART';
|
||||
[!"#$%&'*+,-.`?\\_/] return 'PUNCTUATION';
|
||||
[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|
|
||||
[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|
|
||||
@@ -305,6 +307,10 @@ vertex: idString SQS text SQE
|
||||
{$$ = $1;yy.addVertex($1,$3,'ellipse');}
|
||||
| idString '(-' text '-)' spaceList
|
||||
{$$ = $1;yy.addVertex($1,$3,'ellipse');}
|
||||
| idString STADIUMSTART text STADIUMEND
|
||||
{$$ = $1;yy.addVertex($1,$3,'stadium');}
|
||||
| idString STADIUMSTART text STADIUMEND spaceList
|
||||
{$$ = $1;yy.addVertex($1,$3,'stadium');}
|
||||
| idString PS text PE
|
||||
{$$ = $1;yy.addVertex($1,$3,'round');}
|
||||
| idString PS text PE spaceList
|
||||
@@ -460,13 +466,6 @@ text: textToken
|
||||
|
||||
|
||||
|
||||
commentText: commentToken
|
||||
{$$=$1;}
|
||||
| commentText commentToken
|
||||
{$$=$1+''+$2;}
|
||||
;
|
||||
|
||||
|
||||
keywords
|
||||
: STYLE | LINKSTYLE | CLASSDEF | CLASS | CLICK | GRAPH | DIR | subgraph | end | DOWN | UP;
|
||||
|
||||
@@ -516,8 +515,6 @@ linkStyleStatement
|
||||
{$$ = $1;yy.updateLinkInterpolate($3,$7);}
|
||||
;
|
||||
|
||||
commentStatement: PCT PCT commentText;
|
||||
|
||||
numList: NUM
|
||||
{$$ = [$1]}
|
||||
| numList COMMA NUM
|
||||
@@ -539,8 +536,6 @@ styleComponent: ALPHA | COLON | MINUS | NUM | UNIT | SPACE | HEX | BRKT | DOT |
|
||||
|
||||
/* Token lists */
|
||||
|
||||
commentToken : textToken | graphCodeTokens ;
|
||||
|
||||
textToken : textNoTagsToken | TAGSTART | TAGEND | '==' | '--' | PCT | DEFAULT;
|
||||
|
||||
textNoTagsToken: alphaNumToken | SPACE | MINUS | keywords ;
|
||||
@@ -574,5 +569,5 @@ alphaNumToken : PUNCTUATION | UNICODE_TEXT | NUM| ALPHA | COLON | COMMA | PLUS
|
||||
|
||||
idStringToken : ALPHA|UNDERSCORE |UNICODE_TEXT | NUM| COLON | COMMA | PLUS | MINUS | DOWN |EQUALS | MULT | BRKT | DOT | PUNCTUATION;
|
||||
|
||||
graphCodeTokens: TRAPSTART | TRAPEND | INVTRAPSTART | INVTRAPEND | PIPE | PS | PE | SQS | SQE | DIAMOND_START | DIAMOND_STOP | TAGSTART | TAGEND | ARROW_CROSS | ARROW_POINT | ARROW_CIRCLE | ARROW_OPEN | QUOTE | SEMI ;
|
||||
graphCodeTokens: STADIUMSTART | STADIUMEND | TRAPSTART | TRAPEND | INVTRAPSTART | INVTRAPEND | PIPE | PS | PE | SQS | SQE | DIAMOND_START | DIAMOND_STOP | TAGSTART | TAGEND | ARROW_CROSS | ARROW_POINT | ARROW_CIRCLE | ARROW_OPEN | QUOTE | SEMI;
|
||||
%%
|
||||
|
@@ -83,7 +83,7 @@ describe('when parsing subgraphs', function() {
|
||||
const subgraph = subgraphs[0];
|
||||
expect(subgraph.nodes.length).toBe(1);
|
||||
expect(subgraph.nodes[0]).toBe('A');
|
||||
expect(subgraph.id).toBe('s1test');
|
||||
expect(subgraph.id).toBe('1test');
|
||||
});
|
||||
|
||||
it('should handle subgraphs1', function() {
|
||||
|
@@ -134,18 +134,32 @@ const getStartDate = function(prevTime, dateFormat, str) {
|
||||
str = str.trim();
|
||||
|
||||
// Test for after
|
||||
const re = /^after\s+([\d\w-]+)/;
|
||||
const re = /^after\s+([\d\w- ]+)/;
|
||||
const afterStatement = re.exec(str.trim());
|
||||
|
||||
if (afterStatement !== null) {
|
||||
const task = findTaskById(afterStatement[1]);
|
||||
// check all after ids and take the latest
|
||||
let latestEndingTask = null;
|
||||
afterStatement[1].split(' ').forEach(function(id) {
|
||||
let task = findTaskById(id);
|
||||
if (typeof task !== 'undefined') {
|
||||
if (!latestEndingTask) {
|
||||
latestEndingTask = task;
|
||||
} else {
|
||||
if (task.endTime > latestEndingTask.endTime) {
|
||||
latestEndingTask = task;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof task === 'undefined') {
|
||||
if (!latestEndingTask) {
|
||||
const dt = new Date();
|
||||
dt.setHours(0, 0, 0, 0);
|
||||
return dt;
|
||||
} else {
|
||||
return latestEndingTask.endTime;
|
||||
}
|
||||
return task.endTime;
|
||||
}
|
||||
|
||||
// Check for actual date set
|
||||
|
@@ -73,7 +73,7 @@ export const drawDescrState = (g, stateDef) => {
|
||||
const title = g
|
||||
.append('text')
|
||||
.attr('x', 2 * getConfig().state.padding)
|
||||
.attr('y', getConfig().state.textHeight + 1.5 * getConfig().state.padding)
|
||||
.attr('y', getConfig().state.textHeight + 1.3 * getConfig().state.padding)
|
||||
.attr('font-size', getConfig().state.fontSize)
|
||||
.attr('class', 'state-title')
|
||||
.text(stateDef.descriptions[0]);
|
||||
@@ -87,7 +87,7 @@ export const drawDescrState = (g, stateDef) => {
|
||||
.attr(
|
||||
'y',
|
||||
titleHeight +
|
||||
getConfig().state.padding * 0.2 +
|
||||
getConfig().state.padding * 0.4 +
|
||||
getConfig().state.dividerMargin +
|
||||
getConfig().state.textHeight
|
||||
)
|
||||
@@ -129,71 +129,108 @@ export const drawDescrState = (g, stateDef) => {
|
||||
* Adds the creates a box around the existing content and adds a
|
||||
* panel for the id on top of the content.
|
||||
*/
|
||||
export const addIdAndBox = (g, stateDef) => {
|
||||
// TODO Move hardcodings to conf
|
||||
// const addTspan = function(textEl, txt, isFirst) {
|
||||
// const tSpan = textEl
|
||||
// .append('tspan')
|
||||
// .attr('x', 2 * getConfig().state.padding)
|
||||
// .text(txt);
|
||||
// if (!isFirst) {
|
||||
// tSpan.attr('dy', getConfig().state.textHeight);
|
||||
// }
|
||||
// };
|
||||
/**
|
||||
* Function that creates an title row and a frame around a substate for a composit state diagram.
|
||||
* The function returns a new d3 svg object with updated width and height properties;
|
||||
* @param {*} g The d3 svg object for the substate to framed
|
||||
* @param {*} stateDef The info about the
|
||||
*/
|
||||
export const addTitleAndBox = (g, stateDef, altBkg) => {
|
||||
const pad = getConfig().state.padding;
|
||||
const dblPad = 2 * getConfig().state.padding;
|
||||
const orgBox = g.node().getBBox();
|
||||
const orgWidth = orgBox.width;
|
||||
const orgX = orgBox.x;
|
||||
|
||||
const title = g
|
||||
.append('text')
|
||||
.attr('x', 2 * getConfig().state.padding)
|
||||
.attr('x', 0)
|
||||
.attr('y', getConfig().state.titleShift)
|
||||
.attr('font-size', getConfig().state.fontSize)
|
||||
.attr('class', 'state-title')
|
||||
.text(stateDef.id);
|
||||
|
||||
const titleBox = title.node().getBBox();
|
||||
|
||||
const lineY = 1 - getConfig().state.textHeight;
|
||||
const descrLine = g
|
||||
.append('line') // text label for the x axis
|
||||
.attr('x1', 0)
|
||||
.attr('y1', lineY)
|
||||
.attr('y2', lineY)
|
||||
.attr('class', 'descr-divider');
|
||||
const titleWidth = titleBox.width + dblPad;
|
||||
let width = Math.max(titleWidth, orgWidth); // + dblPad;
|
||||
if (width === orgWidth) {
|
||||
width = width + dblPad;
|
||||
}
|
||||
let startX;
|
||||
// const lineY = 1 - getConfig().state.textHeight;
|
||||
// const descrLine = g
|
||||
// .append('line') // text label for the x axis
|
||||
// .attr('x1', 0)
|
||||
// .attr('y1', lineY)
|
||||
// .attr('y2', lineY)
|
||||
// .attr('class', 'descr-divider');
|
||||
|
||||
const graphBox = g.node().getBBox();
|
||||
title.attr('x', graphBox.width / 2 - titleBox.width / 2);
|
||||
descrLine.attr('x2', graphBox.width + getConfig().state.padding);
|
||||
// console.warn(width / 2, titleWidth / 2, getConfig().state.padding, orgBox);
|
||||
// descrLine.attr('x2', graphBox.width + getConfig().state.padding);
|
||||
|
||||
if (stateDef.doc) {
|
||||
// cnsole.warn(
|
||||
// stateDef.id,
|
||||
// 'orgX: ',
|
||||
// orgX,
|
||||
// 'width: ',
|
||||
// width,
|
||||
// 'titleWidth: ',
|
||||
// titleWidth,
|
||||
// 'orgWidth: ',
|
||||
// orgWidth,
|
||||
// 'width',
|
||||
// width
|
||||
// );
|
||||
}
|
||||
|
||||
startX = orgX - pad;
|
||||
if (titleWidth > orgWidth) {
|
||||
startX = (orgWidth - width) / 2 + pad;
|
||||
}
|
||||
if (Math.abs(orgX - graphBox.x) < pad) {
|
||||
if (titleWidth > orgWidth) {
|
||||
startX = orgX - (titleWidth - orgWidth) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
const lineY = 1 - getConfig().state.textHeight;
|
||||
// White color
|
||||
g.insert('rect', ':first-child')
|
||||
.attr('x', graphBox.x)
|
||||
.attr('x', startX)
|
||||
.attr('y', lineY)
|
||||
.attr('class', 'composit')
|
||||
.attr('width', graphBox.width + getConfig().state.padding)
|
||||
.attr('class', altBkg ? 'alt-composit' : 'composit')
|
||||
.attr('width', width)
|
||||
.attr(
|
||||
'height',
|
||||
graphBox.height + getConfig().state.textHeight + getConfig().state.titleShift + 1
|
||||
)
|
||||
.attr('rx', '0');
|
||||
|
||||
title.attr('x', startX + pad);
|
||||
if (titleWidth <= orgWidth) title.attr('x', orgX + (width - dblPad) / 2 - titleWidth / 2 + pad);
|
||||
|
||||
// Title background
|
||||
g.insert('rect', ':first-child')
|
||||
.attr('x', graphBox.x)
|
||||
.attr('x', startX)
|
||||
.attr(
|
||||
'y',
|
||||
getConfig().state.titleShift - getConfig().state.textHeight - getConfig().state.padding
|
||||
)
|
||||
.attr('width', graphBox.width + getConfig().state.padding)
|
||||
.attr('width', width)
|
||||
// Just needs to be higher then the descr line, will be clipped by the white color box
|
||||
.attr('height', getConfig().state.textHeight * 3)
|
||||
.attr('rx', getConfig().state.radius);
|
||||
|
||||
// Full background
|
||||
g.insert('rect', ':first-child')
|
||||
.attr('x', graphBox.x)
|
||||
.attr('x', startX)
|
||||
.attr(
|
||||
'y',
|
||||
getConfig().state.titleShift - getConfig().state.textHeight - getConfig().state.padding
|
||||
)
|
||||
.attr('width', graphBox.width + getConfig().state.padding)
|
||||
.attr('width', width)
|
||||
.attr('height', graphBox.height + 3 + 2 * getConfig().state.textHeight)
|
||||
.attr('rx', getConfig().state.radius);
|
||||
|
||||
|
@@ -5,40 +5,19 @@ import { logger } from '../../logger';
|
||||
import stateDb from './stateDb';
|
||||
import { parser } from './parser/stateDiagram';
|
||||
// import idCache from './id-cache';
|
||||
import { drawState, addIdAndBox, drawEdge } from './shapes';
|
||||
import { drawState, addTitleAndBox, drawEdge } from './shapes';
|
||||
import { getConfig } from '../../config';
|
||||
|
||||
parser.yy = stateDb;
|
||||
|
||||
// TODO Move conf object to main conf in mermaidAPI
|
||||
let conf;
|
||||
// {
|
||||
// // Used
|
||||
// padding: 5,
|
||||
// // Font size factor, this is used to guess the width of the edges labels before rendering by dagre
|
||||
// // layout. This might need updating if/when switching font
|
||||
// fontSizeFactor: 5.02,
|
||||
// labelHeight: 16,
|
||||
// edgeLengthFactor: '20',
|
||||
// compositTitleSize: 35
|
||||
// };
|
||||
|
||||
const transformationLog = {};
|
||||
|
||||
export const setConf = function() {};
|
||||
|
||||
// Todo optimize
|
||||
// const getGraphId = function(label) {
|
||||
// const keys = idCache.keys();
|
||||
|
||||
// for (let i = 0; i < keys.length; i++) {
|
||||
// if (idCache.get(keys[i]).label === label) {
|
||||
// return keys[i];
|
||||
// }
|
||||
// }
|
||||
|
||||
// return undefined;
|
||||
// };
|
||||
|
||||
/**
|
||||
* Setup arrow head and define the marker. The result is appended to the svg.
|
||||
@@ -68,11 +47,11 @@ export const draw = function(text, id) {
|
||||
parser.parse(text);
|
||||
logger.debug('Rendering diagram ' + text);
|
||||
|
||||
// /// / Fetch the default direction, use TD if none was found
|
||||
// Fetch the default direction, use TD if none was found
|
||||
const diagram = d3.select(`[id='${id}']`);
|
||||
insertMarkers(diagram);
|
||||
|
||||
// // Layout graph, Create a new directed graph
|
||||
// Layout graph, Create a new directed graph
|
||||
const graph = new graphlib.Graph({
|
||||
multigraph: false,
|
||||
compound: true,
|
||||
@@ -81,19 +60,17 @@ export const draw = function(text, id) {
|
||||
// ranksep: '20'
|
||||
});
|
||||
|
||||
// // Default to assigning a new object as a label for each new edge.
|
||||
// Default to assigning a new object as a label for each new edge.
|
||||
graph.setDefaultEdgeLabel(function() {
|
||||
return {};
|
||||
});
|
||||
|
||||
const rootDoc = stateDb.getRootDoc();
|
||||
renderDoc(rootDoc, diagram);
|
||||
renderDoc(rootDoc, diagram, undefined, false);
|
||||
|
||||
const padding = conf.padding;
|
||||
const bounds = diagram.node().getBBox();
|
||||
|
||||
console.warn(bounds);
|
||||
|
||||
const width = bounds.width + padding * 2;
|
||||
const height = bounds.height + padding * 2;
|
||||
|
||||
@@ -102,7 +79,7 @@ export const draw = function(text, id) {
|
||||
// diagram.attr('height', height);
|
||||
|
||||
// Zoom in a bit
|
||||
diagram.attr('width', width * 2);
|
||||
diagram.attr('width', width * 1.75);
|
||||
// diagram.attr('height', bounds.height * 3 + conf.padding * 2);
|
||||
diagram.attr(
|
||||
'viewBox',
|
||||
@@ -130,12 +107,21 @@ const getRows = s => {
|
||||
return str.split('#br#');
|
||||
};
|
||||
|
||||
const renderDoc = (doc, diagram, parentId) => {
|
||||
const renderDoc = (doc, diagram, parentId, altBkg) => {
|
||||
// // Layout graph, Create a new directed graph
|
||||
const graph = new graphlib.Graph({
|
||||
compound: true
|
||||
});
|
||||
|
||||
let i;
|
||||
let edgeFreeDoc = true;
|
||||
for (i = 0; i < doc.length; i++) {
|
||||
if (doc[i].stmt === 'relation') {
|
||||
edgeFreeDoc = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Set an object for the graph label
|
||||
if (parentId)
|
||||
graph.setGraph({
|
||||
@@ -144,8 +130,11 @@ const renderDoc = (doc, diagram, parentId) => {
|
||||
compound: true,
|
||||
// acyclicer: 'greedy',
|
||||
ranker: 'tight-tree',
|
||||
ranksep: conf.edgeLengthFactor
|
||||
ranksep: edgeFreeDoc ? 1 : conf.edgeLengthFactor,
|
||||
nodeSep: edgeFreeDoc ? 1 : 50
|
||||
// isMultiGraph: false
|
||||
// ranksep: 5,
|
||||
// nodesep: 1
|
||||
});
|
||||
else {
|
||||
graph.setGraph({
|
||||
@@ -154,7 +143,8 @@ const renderDoc = (doc, diagram, parentId) => {
|
||||
// isCompound: true,
|
||||
// acyclicer: 'greedy',
|
||||
// ranker: 'longest-path'
|
||||
ranksep: conf.edgeLengthFactor,
|
||||
ranksep: edgeFreeDoc ? 1 : conf.edgeLengthFactor,
|
||||
nodeSep: edgeFreeDoc ? 1 : 50,
|
||||
ranker: 'tight-tree'
|
||||
// ranker: 'network-simplex'
|
||||
// isMultiGraph: false
|
||||
@@ -187,14 +177,14 @@ const renderDoc = (doc, diagram, parentId) => {
|
||||
.append('g')
|
||||
.attr('id', stateDef.id)
|
||||
.attr('class', 'stateGroup');
|
||||
node = renderDoc(stateDef.doc, sub, stateDef.id);
|
||||
node = renderDoc(stateDef.doc, sub, stateDef.id, !altBkg);
|
||||
|
||||
if (first) {
|
||||
// first = false;
|
||||
sub = addIdAndBox(sub, stateDef);
|
||||
sub = addTitleAndBox(sub, stateDef, altBkg);
|
||||
let boxBounds = sub.node().getBBox();
|
||||
node.width = boxBounds.width;
|
||||
node.height = boxBounds.height + 2 * conf.padding;
|
||||
node.height = boxBounds.height + conf.padding / 2;
|
||||
transformationLog[stateDef.id] = { y: conf.compositTitleSize };
|
||||
} else {
|
||||
// sub = addIdAndBox(sub, stateDef);
|
||||
@@ -280,8 +270,8 @@ const renderDoc = (doc, diagram, parentId) => {
|
||||
pShift = 0;
|
||||
}
|
||||
}
|
||||
divider.setAttribute('x1', 0 - pShift);
|
||||
divider.setAttribute('x2', pWidth - pShift);
|
||||
divider.setAttribute('x1', 0 - pShift + 8);
|
||||
divider.setAttribute('x2', pWidth - pShift - 8);
|
||||
});
|
||||
} else {
|
||||
logger.debug('No Node ' + v + ': ' + JSON.stringify(graph.node(v)));
|
||||
|
@@ -585,23 +585,23 @@ const render = function(id, txt, cb, container) {
|
||||
.selectAll('foreignobject > *')
|
||||
.attr('xmlns', 'http://www.w3.org/1999/xhtml');
|
||||
|
||||
let url = '';
|
||||
if (config.arrowMarkerAbsolute) {
|
||||
url =
|
||||
window.location.protocol +
|
||||
'//' +
|
||||
window.location.host +
|
||||
window.location.pathname +
|
||||
window.location.search;
|
||||
url = url.replace(/\(/g, '\\(');
|
||||
url = url.replace(/\)/g, '\\)');
|
||||
}
|
||||
// if (config.arrowMarkerAbsolute) {
|
||||
// url =
|
||||
// window.location.protocol +
|
||||
// '//' +
|
||||
// window.location.host +
|
||||
// window.location.pathname +
|
||||
// window.location.search;
|
||||
// url = url.replace(/\(/g, '\\(');
|
||||
// url = url.replace(/\)/g, '\\)');
|
||||
// }
|
||||
|
||||
// Fix for when the base tag is used
|
||||
let svgCode = d3
|
||||
.select('#d' + id)
|
||||
.node()
|
||||
.innerHTML.replace(/url\(#arrowhead/g, 'url(' + url + '#arrowhead', 'g');
|
||||
let svgCode = d3.select('#d' + id).node().innerHTML;
|
||||
|
||||
if (!config.arrowMarkerAbsolute || config.arrowMarkerAbsolute === 'false') {
|
||||
svgCode = svgCode.replace(/marker-end="url\(.*?#/g, 'marker-end="url(#', 'g');
|
||||
}
|
||||
|
||||
svgCode = decodeEntities(svgCode);
|
||||
|
||||
@@ -686,7 +686,7 @@ export default mermaidAPI;
|
||||
* ## mermaidAPI configuration defaults
|
||||
* <pre>
|
||||
*
|
||||
* <script>
|
||||
* <script>
|
||||
* var config = {
|
||||
* theme:'default',
|
||||
* logLevel:'fatal',
|
||||
@@ -728,6 +728,6 @@ export default mermaidAPI;
|
||||
* }
|
||||
* };
|
||||
* mermaid.initialize(config);
|
||||
* </script>
|
||||
* </script>
|
||||
*</pre>
|
||||
*/
|
||||
|
@@ -37,6 +37,11 @@ g.stateGroup line {
|
||||
border-bottom: 1px
|
||||
}
|
||||
|
||||
.stateGroup .alt-composit {
|
||||
fill: #e0e0e0;
|
||||
border-bottom: 1px
|
||||
}
|
||||
|
||||
.state-note {
|
||||
stroke: $noteBorderColor;
|
||||
fill: $noteBkgColor;
|
||||
|
@@ -1,10 +1,10 @@
|
||||
import path from 'path'
|
||||
import path from 'path';
|
||||
|
||||
const amdRule = {
|
||||
parser: {
|
||||
amd: false // https://github.com/lodash/lodash/issues/3052
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const jisonRule = {
|
||||
test: /\.jison$/,
|
||||
@@ -14,7 +14,7 @@ const jisonRule = {
|
||||
'token-stack': true
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const jsRule = {
|
||||
test: /\.js$/,
|
||||
include: [
|
||||
@@ -24,16 +24,13 @@ const jsRule = {
|
||||
use: {
|
||||
loader: 'babel-loader'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const scssRule = { // load scss to string
|
||||
const scssRule = {
|
||||
// load scss to string
|
||||
test: /\.scss$/,
|
||||
use: [
|
||||
{ loader: 'css-to-string-loader' },
|
||||
{ loader: 'css-loader' },
|
||||
{ loader: 'sass-loader' }
|
||||
]
|
||||
}
|
||||
use: [{ loader: 'css-to-string-loader' }, { loader: 'css-loader' }, { loader: 'sass-loader' }]
|
||||
};
|
||||
|
||||
export const jsConfig = () => {
|
||||
return {
|
||||
@@ -59,5 +56,5 @@ export const jsConfig = () => {
|
||||
rules: [amdRule, jsRule, scssRule, jisonRule]
|
||||
},
|
||||
devtool: 'source-map'
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
Reference in New Issue
Block a user