mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-28 07:03:17 +08:00
Merge branch 'develop' into origin/3258_Flowchart_nodeSpacing_Subgraph
This commit is contained in:
commit
5935e277e6
137
.cspell/code-terms.txt
Normal file
137
.cspell/code-terms.txt
Normal file
@ -0,0 +1,137 @@
|
||||
# This file contains coding related terms
|
||||
ALPHANUM
|
||||
antiscript
|
||||
APPLYCLASS
|
||||
ARROWHEADSTYLE
|
||||
ARROWTYPE
|
||||
autonumber
|
||||
axisl-line
|
||||
Bigdecimal
|
||||
birel
|
||||
BIREL
|
||||
bqstring
|
||||
BQUOTE
|
||||
bramp
|
||||
BRKT
|
||||
callbackargs
|
||||
callbackname
|
||||
classdef
|
||||
classdefid
|
||||
classentity
|
||||
classname
|
||||
COLONSEP
|
||||
COMPOSIT_STATE
|
||||
concat
|
||||
controlx
|
||||
controly
|
||||
CSSCLASS
|
||||
CYLINDEREND
|
||||
CYLINDERSTART
|
||||
datakey
|
||||
DEND
|
||||
descr
|
||||
distp
|
||||
distq
|
||||
divs
|
||||
docref
|
||||
DOMID
|
||||
doublecircle
|
||||
DOUBLECIRCLEEND
|
||||
DOUBLECIRCLESTART
|
||||
DQUOTE
|
||||
DSTART
|
||||
edgesep
|
||||
EMPTYSTR
|
||||
enddate
|
||||
ERDIAGRAM
|
||||
flatmap
|
||||
forwardable
|
||||
frontmatter
|
||||
funs
|
||||
gantt
|
||||
GENERICTYPE
|
||||
getBoundarys
|
||||
grammr
|
||||
graphtype
|
||||
interp
|
||||
introdcued
|
||||
INVTRAPEND
|
||||
INVTRAPSTART
|
||||
JDBC
|
||||
jison
|
||||
Kaufmann
|
||||
keyify
|
||||
LABELPOS
|
||||
LABELTYPE
|
||||
lcov
|
||||
LEFTOF
|
||||
Lexa
|
||||
linebreak
|
||||
LINETYPE
|
||||
LINKSTYLE
|
||||
LLABEL
|
||||
loglevel
|
||||
LOGMSG
|
||||
lookaheads
|
||||
mdast
|
||||
minlen
|
||||
Mstartx
|
||||
MULT
|
||||
NODIR
|
||||
NSTR
|
||||
Qcontrolx
|
||||
reinit
|
||||
rels
|
||||
reqs
|
||||
rewritelinks
|
||||
rgba
|
||||
RIGHTOF
|
||||
sankey
|
||||
sequencenumber
|
||||
shrc
|
||||
signaltype
|
||||
someclass
|
||||
SPACELINE
|
||||
SPACELIST
|
||||
STADIUMEND
|
||||
STADIUMSTART
|
||||
startdate
|
||||
startx
|
||||
starty
|
||||
STMNT
|
||||
stopx
|
||||
stopy
|
||||
strikethrough
|
||||
stringifying
|
||||
struct
|
||||
STYLECLASS
|
||||
STYLEOPTS
|
||||
subcomponent
|
||||
subcomponents
|
||||
SUBROUTINEEND
|
||||
SUBROUTINESTART
|
||||
Subschemas
|
||||
substr
|
||||
TAGEND
|
||||
TAGSTART
|
||||
techn
|
||||
TESTSTR
|
||||
TEXTDATA
|
||||
TEXTLENGTH
|
||||
titlevalue
|
||||
topbar
|
||||
TRAPEND
|
||||
TRAPSTART
|
||||
ts-nocheck
|
||||
tsdoc
|
||||
typeof
|
||||
typestr
|
||||
unshift
|
||||
verifymethod
|
||||
VERIFYMTHD
|
||||
WARN_DOCSDIR_DOESNT_MATCH
|
||||
xhost
|
||||
yaxis
|
||||
yfunc
|
||||
yytext
|
||||
zenuml
|
8
.cspell/contributors.txt
Normal file
8
.cspell/contributors.txt
Normal file
@ -0,0 +1,8 @@
|
||||
# Contributors to mermaidjs, one per line
|
||||
Ashish Jain
|
||||
cpettitt
|
||||
Dong Cai
|
||||
Nikolay Rozhkov
|
||||
Peng Xiao
|
||||
subhash-halder
|
||||
Vinod Sidharth
|
52
.cspell/cspell.config.yaml
Normal file
52
.cspell/cspell.config.yaml
Normal file
@ -0,0 +1,52 @@
|
||||
# yaml-language-server: $schema=https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json
|
||||
|
||||
$schema: https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json
|
||||
|
||||
dictionaryDefinitions:
|
||||
- name: code-terms
|
||||
path: ./code-terms.txt
|
||||
description: A list of coding related terms.
|
||||
addWords: true
|
||||
- name: mermaid-terms
|
||||
path: ./mermaid-terms.txt
|
||||
description: A list of terms related to the mermaid project.
|
||||
addWords: true
|
||||
- name: misc-terms
|
||||
path: ./misc-terms.txt
|
||||
description: A list of miscellaneous terms.
|
||||
- name: 3rd-party-terms
|
||||
path: ./libraries.txt
|
||||
description: A list of 3rd party terms from dependencies.
|
||||
addWords: true
|
||||
- name: contributors
|
||||
path: ./contributors.txt
|
||||
description: A list of contributors to the mermaid project.
|
||||
type: 'W'
|
||||
addWords: true
|
||||
|
||||
# cspell:disable
|
||||
- name: suggestions
|
||||
words:
|
||||
- none
|
||||
suggestWords:
|
||||
- seperator:separator
|
||||
- vertice:vertex
|
||||
# cspell:enable
|
||||
|
||||
patterns:
|
||||
- name: character-set-cyrillic
|
||||
pattern: '/\p{Script_Extensions=Cyrillic}+/gu'
|
||||
- name: svg-block
|
||||
pattern: '<svg[\S\s]+?</svg>'
|
||||
- name: json-property
|
||||
pattern: '/"[\w/@-]+":/g'
|
||||
|
||||
dictionaries:
|
||||
- mermaid-terms
|
||||
- suggestions
|
||||
- contributors
|
||||
|
||||
ignorePaths:
|
||||
- '*.txt' # do not spell check local dictionaries
|
||||
|
||||
# cspell:dictionary misc-terms
|
70
.cspell/libraries.txt
Normal file
70
.cspell/libraries.txt
Normal file
@ -0,0 +1,70 @@
|
||||
# Add third party library terms below
|
||||
acyclicer
|
||||
Antlr
|
||||
Appli
|
||||
applitools
|
||||
Asciidoctor
|
||||
Astah
|
||||
automerge
|
||||
bilkent
|
||||
bisheng
|
||||
Blazor
|
||||
codedoc
|
||||
Codemia
|
||||
codepaths
|
||||
csstree
|
||||
cytoscape
|
||||
cytoscape-cose-bilkent
|
||||
dagre
|
||||
dagre-d3
|
||||
Deepdwn
|
||||
Docsify
|
||||
Docsy
|
||||
DokuWiki
|
||||
dompurify
|
||||
elkjs
|
||||
fontawesome
|
||||
Foswiki
|
||||
Gitea
|
||||
graphlib
|
||||
Grav
|
||||
iconify
|
||||
Inkdrop
|
||||
jiti
|
||||
jsdocs
|
||||
jsfiddle
|
||||
jsonschema
|
||||
katex
|
||||
khroma
|
||||
mathml
|
||||
matplotlib
|
||||
mdbook
|
||||
Mermerd
|
||||
mkdocs
|
||||
Nextra
|
||||
nodenext
|
||||
npmjs
|
||||
pageview
|
||||
pathe
|
||||
phpbb
|
||||
pixelmatch
|
||||
Podlite
|
||||
presetAttributify
|
||||
pyplot
|
||||
redmine
|
||||
rehype
|
||||
rscratch
|
||||
sparkline
|
||||
sphinxcontrib
|
||||
ssim
|
||||
stylis
|
||||
Swimm
|
||||
tsbuildinfo
|
||||
Tuleap
|
||||
Typora
|
||||
unocss
|
||||
unplugin
|
||||
unstub
|
||||
vite
|
||||
vitest
|
||||
Zune
|
39
.cspell/mermaid-terms.txt
Normal file
39
.cspell/mermaid-terms.txt
Normal file
@ -0,0 +1,39 @@
|
||||
Adamiecki
|
||||
arrowend
|
||||
bmatrix
|
||||
braintree
|
||||
catmull
|
||||
compositTitleSize
|
||||
doublecircle
|
||||
elems
|
||||
gantt
|
||||
gitgraph
|
||||
gzipped
|
||||
knsv
|
||||
Knut
|
||||
marginx
|
||||
marginy
|
||||
Markdownish
|
||||
mermaidjs
|
||||
mindmap
|
||||
mindmaps
|
||||
multigraph
|
||||
nodesep
|
||||
NOTEGROUP
|
||||
Pinterest
|
||||
rankdir
|
||||
ranksep
|
||||
rect
|
||||
rects
|
||||
sandboxed
|
||||
siebling
|
||||
statediagram
|
||||
substate
|
||||
Sveidqvist
|
||||
unfixable
|
||||
Viewbox
|
||||
viewports
|
||||
visio
|
||||
vitepress
|
||||
xlink
|
||||
xychart
|
1
.cspell/misc-terms.txt
Normal file
1
.cspell/misc-terms.txt
Normal file
@ -0,0 +1 @@
|
||||
newbranch
|
@ -63,13 +63,24 @@ module.exports = {
|
||||
minimumDescriptionLength: 10,
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/naming-convention': [
|
||||
'error',
|
||||
{
|
||||
selector: 'typeLike',
|
||||
format: ['PascalCase'],
|
||||
custom: {
|
||||
regex: '^I[A-Z]',
|
||||
match: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
'json/*': ['error', 'allowComments'],
|
||||
'@cspell/spellchecker': [
|
||||
'error',
|
||||
{
|
||||
checkIdentifiers: false,
|
||||
checkStrings: false,
|
||||
checkStringTemplates: false,
|
||||
checkIdentifiers: true,
|
||||
checkStrings: true,
|
||||
checkStringTemplates: true,
|
||||
},
|
||||
],
|
||||
'no-empty': [
|
||||
@ -148,6 +159,19 @@ module.exports = {
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.spec.{ts,js}', 'tests/**', 'cypress/**/*.js'],
|
||||
rules: {
|
||||
'@cspell/spellchecker': [
|
||||
'error',
|
||||
{
|
||||
checkIdentifiers: false,
|
||||
checkStrings: false,
|
||||
checkStringTemplates: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.html', '*.md', '**/*.md/*'],
|
||||
rules: {
|
||||
|
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -4,7 +4,7 @@ contact_links:
|
||||
url: https://github.com/mermaid-js/mermaid/discussions
|
||||
about: Ask the Community questions or share your own graphs in our discussions.
|
||||
- name: Discord
|
||||
url: https://discord.gg/wwtabKgp8y
|
||||
url: https://discord.gg/AgrbSrBer3
|
||||
about: Join our Community on Discord for Help and a casual chat.
|
||||
- name: Documentation
|
||||
url: https://mermaid.js.org
|
||||
|
5
.github/lychee.toml
vendored
5
.github/lychee.toml
vendored
@ -35,7 +35,10 @@ exclude = [
|
||||
'packages/mermaid/src/docs/config/setup/*',
|
||||
|
||||
# Ignore Discord invite
|
||||
"https://discord.gg"
|
||||
"https://discord.gg",
|
||||
|
||||
# BundlePhobia has frequent downtime
|
||||
"https://bundlephobia.com"
|
||||
]
|
||||
|
||||
# Exclude all private IPs from checking.
|
||||
|
4
.github/pull_request_template.md
vendored
4
.github/pull_request_template.md
vendored
@ -12,7 +12,7 @@ Describe the way your implementation works or what design decisions you made if
|
||||
|
||||
Make sure you
|
||||
|
||||
- [ ] :book: have read the [contribution guidelines](https://github.com/mermaid-js/mermaid/blob/develop/CONTRIBUTING.md)
|
||||
- [ ] :book: have read the [contribution guidelines](https://mermaid.js.org/community/contributing.html)
|
||||
- [ ] :computer: have added necessary unit/e2e tests.
|
||||
- [ ] :notebook: have added documentation. Make sure [`MERMAID_RELEASE_VERSION`](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/docs/community/contributing.md#update-documentation) is used for all new features.
|
||||
- [ ] :notebook: have added documentation. Make sure [`MERMAID_RELEASE_VERSION`](https://mermaid.js.org/community/contributing.html#update-documentation) is used for all new features.
|
||||
- [ ] :bookmark: targeted `develop` branch
|
||||
|
2
.github/workflows/build-docs.yml
vendored
2
.github/workflows/build-docs.yml
vendored
@ -24,7 +24,7 @@ jobs:
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version: 18
|
||||
node-version-file: '.node-version'
|
||||
|
||||
- name: Install Packages
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
7
.github/workflows/build.yml
vendored
7
.github/workflows/build.yml
vendored
@ -15,20 +15,17 @@ permissions:
|
||||
jobs:
|
||||
build-mermaid:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [18.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
# uses version from "packageManager" field in package.json
|
||||
|
||||
- name: Setup Node.js ${{ matrix.node-version }}
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version: ${{ matrix.node-version }}
|
||||
node-version-file: '.node-version'
|
||||
|
||||
- name: Install Packages
|
||||
run: |
|
||||
|
10
.github/workflows/e2e-applitools.yml
vendored
10
.github/workflows/e2e-applitools.yml
vendored
@ -21,9 +21,9 @@ env:
|
||||
jobs:
|
||||
e2e-applitools:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [18.x]
|
||||
container:
|
||||
image: cypress/browsers:node-20.11.0-chrome-121.0.6167.85-1-ff-120.0-edge-121.0.2277.83-1
|
||||
options: --user 1001
|
||||
steps:
|
||||
- if: ${{ ! env.USE_APPLI }}
|
||||
name: Warn if not using Applitools
|
||||
@ -35,10 +35,10 @@ jobs:
|
||||
- uses: pnpm/action-setup@v2
|
||||
# uses version from "packageManager" field in package.json
|
||||
|
||||
- name: Setup Node.js ${{ matrix.node-version }}
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
node-version-file: '.node-version'
|
||||
|
||||
- if: ${{ env.USE_APPLI }}
|
||||
name: Notify applitools of new batch
|
||||
|
13
.github/workflows/e2e.yml
vendored
13
.github/workflows/e2e.yml
vendored
@ -23,13 +23,16 @@ env:
|
||||
jobs:
|
||||
cache:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: cypress/browsers:node-20.11.0-chrome-121.0.6167.85-1-ff-120.0-edge-121.0.2277.83-1
|
||||
options: --user 1001
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.x
|
||||
node-version-file: '.node-version'
|
||||
- name: Cache snapshots
|
||||
id: cache-snapshot
|
||||
uses: actions/cache@v4
|
||||
@ -56,11 +59,13 @@ jobs:
|
||||
|
||||
e2e:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: cypress/browsers:node-20.11.0-chrome-121.0.6167.85-1-ff-120.0-edge-121.0.2277.83-1
|
||||
options: --user 1001
|
||||
needs: cache
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: [18.x]
|
||||
containers: [1, 2, 3, 4]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@ -68,10 +73,10 @@ jobs:
|
||||
- uses: pnpm/action-setup@v2
|
||||
# uses version from "packageManager" field in package.json
|
||||
|
||||
- name: Setup Node.js ${{ matrix.node-version }}
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
node-version-file: '.node-version'
|
||||
|
||||
# These cached snapshots are downloaded, providing the reference snapshots.
|
||||
- name: Cache snapshots
|
||||
|
2
.github/workflows/link-checker.yml
vendored
2
.github/workflows/link-checker.yml
vendored
@ -36,7 +36,7 @@ jobs:
|
||||
restore-keys: cache-lychee-
|
||||
|
||||
- name: Link Checker
|
||||
uses: lycheeverse/lychee-action@v1.9.1
|
||||
uses: lycheeverse/lychee-action@v1.9.3
|
||||
with:
|
||||
args: >-
|
||||
--config .github/lychee.toml
|
||||
|
7
.github/workflows/lint.yml
vendored
7
.github/workflows/lint.yml
vendored
@ -16,20 +16,17 @@ permissions:
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [18.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
# uses version from "packageManager" field in package.json
|
||||
|
||||
- name: Setup Node.js ${{ matrix.node-version }}
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version: ${{ matrix.node-version }}
|
||||
node-version-file: '.node-version'
|
||||
|
||||
- name: Install Packages
|
||||
run: |
|
||||
|
2
.github/workflows/publish-docs.yml
vendored
2
.github/workflows/publish-docs.yml
vendored
@ -31,7 +31,7 @@ jobs:
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version: 18
|
||||
node-version-file: '.node-version'
|
||||
|
||||
- name: Install Packages
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
@ -19,7 +19,7 @@ jobs:
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version: 18.x
|
||||
node-version-file: '.node-version'
|
||||
|
||||
- name: Install Packages
|
||||
run: |
|
||||
|
4
.github/workflows/release-publish.yml
vendored
4
.github/workflows/release-publish.yml
vendored
@ -14,11 +14,11 @@ jobs:
|
||||
- uses: pnpm/action-setup@v2
|
||||
# uses version from "packageManager" field in package.json
|
||||
|
||||
- name: Setup Node.js v18
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version: 18.x
|
||||
node-version-file: '.node-version'
|
||||
|
||||
- name: Install Packages
|
||||
run: |
|
||||
|
7
.github/workflows/test.yml
vendored
7
.github/workflows/test.yml
vendored
@ -8,20 +8,17 @@ permissions:
|
||||
jobs:
|
||||
unit-test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [18.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
# uses version from "packageManager" field in package.json
|
||||
|
||||
- name: Setup Node.js ${{ matrix.node-version }}
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version: ${{ matrix.node-version }}
|
||||
node-version-file: '.node-version'
|
||||
|
||||
- name: Install Packages
|
||||
run: |
|
||||
|
@ -6,6 +6,6 @@ export default {
|
||||
// https://prettier.io/docs/en/cli.html#--cache
|
||||
'prettier --write',
|
||||
],
|
||||
'cSpell.json': ['tsx scripts/fixCSpell.ts'],
|
||||
'.cspell/*.txt': ['tsx scripts/fixCSpell.ts'],
|
||||
'**/*.jison': ['pnpm -w run lint:jison'],
|
||||
};
|
||||
|
1
.node-version
Normal file
1
.node-version
Normal file
@ -0,0 +1 @@
|
||||
v20.11.1
|
1
.npmrc
1
.npmrc
@ -1,3 +1,4 @@
|
||||
registry=https://registry.npmjs.org
|
||||
auto-install-peers=true
|
||||
strict-peer-dependencies=false
|
||||
package-import-method=clone-or-copy
|
||||
|
@ -1,6 +1,7 @@
|
||||
dist
|
||||
cypress/platform/xss3.html
|
||||
.cache
|
||||
.pnpm-store
|
||||
coverage
|
||||
# Autogenerated by PNPM
|
||||
pnpm-lock.yaml
|
||||
@ -12,4 +13,4 @@ stats
|
||||
packages/mermaid/src/config.type.ts
|
||||
# Ignore the files creates in /demos/dev except for example.html
|
||||
demos/dev/**
|
||||
!/demos/dev/example.html
|
||||
!/demos/dev/example.html
|
||||
|
@ -25,6 +25,7 @@ const MERMAID_CONFIG_DIAGRAM_KEYS = [
|
||||
'gitGraph',
|
||||
'c4',
|
||||
'sankey',
|
||||
'block',
|
||||
] as const;
|
||||
|
||||
/**
|
||||
|
2
.vscode/extensions.json
vendored
2
.vscode/extensions.json
vendored
@ -2,7 +2,7 @@
|
||||
"recommendations": [
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode",
|
||||
"zixuanchen.vitest-explorer",
|
||||
"vitest.explorer",
|
||||
"luniclynx.bison"
|
||||
]
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
FROM node:18.19.0-alpine3.18 AS base
|
||||
FROM node:20.11.0-alpine3.19 AS base
|
||||
RUN wget -qO- https://get.pnpm.io/install.sh | ENV="$HOME/.shrc" SHELL="$(which sh)" sh -
|
||||
|
42
README.md
42
README.md
@ -15,7 +15,7 @@ Generate diagrams from markdown-like text.
|
||||
<a href="https://mermaid.live/"><b>Live Editor!</b></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://mermaid.js.org">📖 Documentation</a> | <a href="https://mermaid.js.org/intro/">🚀 Getting Started</a> | <a href="https://www.jsdelivr.com/package/npm/mermaid">🌐 CDN</a> | <a href="https://discord.gg/wwtabKgp8y" title="Discord invite">🙌 Join Us</a>
|
||||
<a href="https://mermaid.js.org">📖 Documentation</a> | <a href="https://mermaid.js.org/intro/">🚀 Getting Started</a> | <a href="https://www.jsdelivr.com/package/npm/mermaid">🌐 CDN</a> | <a href="https://discord.gg/AgrbSrBer3" title="Discord invite">🙌 Join Us</a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="./README.zh-CN.md">简体中文</a>
|
||||
@ -33,7 +33,7 @@ Try Live Editor previews of future releases: <a href="https://develop.git.mermai
|
||||
[![Coverage Status](https://codecov.io/github/mermaid-js/mermaid/branch/develop/graph/badge.svg)](https://app.codecov.io/github/mermaid-js/mermaid/tree/develop)
|
||||
[![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid)
|
||||
[![NPM Downloads](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid)
|
||||
[![Join our Discord!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=discord&label=discord)](https://discord.gg/wwtabKgp8y)
|
||||
[![Join our Discord!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=discord&label=discord)](https://discord.gg/AgrbSrBer3)
|
||||
[![Twitter Follow](https://img.shields.io/badge/Social-mermaidjs__-blue?style=social&logo=X)](https://twitter.com/mermaidjs_)
|
||||
|
||||
<img src="./img/header.png" alt="" />
|
||||
@ -42,7 +42,7 @@ Try Live Editor previews of future releases: <a href="https://develop.git.mermai
|
||||
|
||||
**Thanks to all involved, people committing pull requests, people answering questions! 🙏**
|
||||
|
||||
<a href="https://mermaid-js.github.io/mermaid/landing/"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/intro/img/book-banner-post-release.jpg" alt="Explore Mermaid.js in depth, with real-world examples, tips & tricks from the creator... The first official book on Mermaid is available for purchase. Check it out!"></a>
|
||||
<a href="https://mermaid.js.org/landing/"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/intro/img/book-banner-post-release.jpg" alt="Explore Mermaid.js in depth, with real-world examples, tips & tricks from the creator... The first official book on Mermaid is available for purchase. Check it out!"></a>
|
||||
|
||||
## Table of content
|
||||
|
||||
@ -53,7 +53,7 @@ Try Live Editor previews of future releases: <a href="https://develop.git.mermai
|
||||
- [Examples](#examples)
|
||||
- [Release](#release)
|
||||
- [Related projects](#related-projects)
|
||||
- [Contributors](#contributors)
|
||||
- [Contributors](#contributors---)
|
||||
- [Security and safe diagrams](#security-and-safe-diagrams)
|
||||
- [Reporting vulnerabilities](#reporting-vulnerabilities)
|
||||
- [Appreciation](#appreciation)
|
||||
@ -74,12 +74,12 @@ Mermaid addresses this problem by enabling users to create easily modifiable dia
|
||||
<br/>
|
||||
|
||||
Mermaid allows even non-programmers to easily create detailed diagrams through the [Mermaid Live Editor](https://mermaid.live/).<br/>
|
||||
For video tutorials, visit our [Tutorials](./docs/ecosystem/tutorials.md) page.
|
||||
Use Mermaid with your favorite applications, check out the list of [Integrations and Usages of Mermaid](./docs/ecosystem/integrations-community.md).
|
||||
For video tutorials, visit our [Tutorials](https://mermaid.js.org/ecosystem/tutorials.html) page.
|
||||
Use Mermaid with your favorite applications, check out the list of [Integrations and Usages of Mermaid](https://mermaid.js.org/ecosystem/integrations-community.html).
|
||||
|
||||
You can also use Mermaid within [GitHub](https://github.blog/2022-02-14-include-diagrams-markdown-files-mermaid/) as well many of your other favorite applications—check out the list of [Integrations and Usages of Mermaid](./docs/ecosystem/integrations-community.md).
|
||||
You can also use Mermaid within [GitHub](https://github.blog/2022-02-14-include-diagrams-markdown-files-mermaid/) as well many of your other favorite applications—check out the list of [Integrations and Usages of Mermaid](https://mermaid.js.org/ecosystem/integrations-community.html).
|
||||
|
||||
For a more detailed introduction to Mermaid and some of its more basic uses, look to the [Beginner's Guide](./docs/intro/getting-started.md), [Usage](./docs/config/usage.md) and [Tutorials](./docs/ecosystem/tutorials.md).
|
||||
For a more detailed introduction to Mermaid and some of its more basic uses, look to the [Beginner's Guide](https://mermaid.js.org/intro/getting-started.html), [Usage](https://mermaid.js.org/config/usage.html) and [Tutorials](https://mermaid.js.org/ecosystem/tutorials.html).
|
||||
|
||||
In our release process we rely heavily on visual regression tests using [applitools](https://applitools.com/). Applitools is a great service which has been easy to use and integrate with our tests.
|
||||
|
||||
@ -91,11 +91,11 @@ In our release process we rely heavily on visual regression tests using [applito
|
||||
|
||||
## Examples
|
||||
|
||||
**The following are some examples of the diagrams, charts and graphs that can be made using Mermaid. Click here to jump into the [text syntax](https://mermaid-js.github.io/mermaid/#/n00b-syntaxReference).**
|
||||
**The following are some examples of the diagrams, charts and graphs that can be made using Mermaid. Click here to jump into the [text syntax](https://mermaid.js.org/intro/syntax-reference.html).**
|
||||
|
||||
<!-- <Flowchart> -->
|
||||
|
||||
### Flowchart [<a href="https://mermaid-js.github.io/mermaid/#/flowchart">docs</a> - <a href="https://mermaid.live/edit#pako:eNpNkMtqwzAQRX9FzKqFJK7t1km8KDQP6KJQSLOLvZhIY1tgS0GWmgbb_165IaFaiXvOFTPqgGtBkEJR6zOv0Fj2scsU8-ft8I5G5Gw6fe339GN7tnrYaafE45WvRsLW3Ya4bKVWwzVe_xU-FfVsc9hR62rLwvw_2591z7Y3FuUwgYZMg1L4ObrRzMBW1FAGqb8KKtCLGWRq8Ko7CbS0FdJqA2mBdUsTQGf110VxSK1xdJM2EkuDzd2qNQrypQ7s5TQuXcrW-ie5VoUsx9yZ2seVtac2DYIRz0ppK3eccd0ErRTjD1XfyyRIomSBUUzJPMaXOBb8GC4XRfQcFmL-FEYIwzD8AggvcHE">live editor</a>]
|
||||
### Flowchart [<a href="https://mermaid.js.org/syntax/flowchart.html">docs</a> - <a href="https://mermaid.live/edit#pako:eNpNkMtqwzAQRX9FzKqFJK7t1km8KDQP6KJQSLOLvZhIY1tgS0GWmgbb_165IaFaiXvOFTPqgGtBkEJR6zOv0Fj2scsU8-ft8I5G5Gw6fe339GN7tnrYaafE45WvRsLW3Ya4bKVWwzVe_xU-FfVsc9hR62rLwvw_2591z7Y3FuUwgYZMg1L4ObrRzMBW1FAGqb8KKtCLGWRq8Ko7CbS0FdJqA2mBdUsTQGf110VxSK1xdJM2EkuDzd2qNQrypQ7s5TQuXcrW-ie5VoUsx9yZ2seVtac2DYIRz0ppK3eccd0ErRTjD1XfyyRIomSBUUzJPMaXOBb8GC4XRfQcFmL-FEYIwzD8AggvcHE">live editor</a>]
|
||||
|
||||
```
|
||||
flowchart LR
|
||||
@ -115,12 +115,12 @@ C -->|One| D[Result 1]
|
||||
C -->|Two| E[Result 2]
|
||||
```
|
||||
|
||||
### Sequence diagram [<a href="https://mermaid-js.github.io/mermaid/#/sequenceDiagram">docs</a> - <a href="https://mermaid.live/edit#pako:eNo9kMluwjAQhl_F-AykQMuSA1WrbuLQQ3v1ZbAnsVXHkzrjVhHi3etQwKfRv4w-z0FqMihL2eF3wqDxyUEdoVHhwTuNk-12RzaU4g29JzHMY2HpV0BE0VO6V8ETtdkGz1Zb1F8qiPyG5LX84mrLAmpwoWNh-5a0pWCiAxUwGBXeiVHEU4oq8V_6AHYUwAu2lLLTjVQ4bc1rT2yleI0IfJG320faZ9ABbk-Jz3hZnFxBduR9L2oiM5Jj2WBswJn8-cMArSRbbFDJMo8GK0ielVThmKOpNcD4bBxTlGUFvsOxhMT02QctS44JL6HzAS-iJzCYOwfJfTscunYd542aQuXqQU_RZ9kyt11ZFIM9rR3btJ9qaorOGQuR7c9mWSznyzXMF7hcLeBusTB6P9usq_ntrDKrm9kc5PF4_AMJE56Z">live editor</a>]
|
||||
### Sequence diagram [<a href="https://mermaid.js.org/syntax/sequenceDiagram.html">docs</a> - <a href="https://mermaid.live/edit#pako:eNo9kMluwjAQhl_F-AykQMuSA1WrbuLQQ3v1ZbAnsVXHkzrjVhHi3etQwKfRv4w-z0FqMihL2eF3wqDxyUEdoVHhwTuNk-12RzaU4g29JzHMY2HpV0BE0VO6V8ETtdkGz1Zb1F8qiPyG5LX84mrLAmpwoWNh-5a0pWCiAxUwGBXeiVHEU4oq8V_6AHYUwAu2lLLTjVQ4bc1rT2yleI0IfJG320faZ9ABbk-Jz3hZnFxBduR9L2oiM5Jj2WBswJn8-cMArSRbbFDJMo8GK0ielVThmKOpNcD4bBxTlGUFvsOxhMT02QctS44JL6HzAS-iJzCYOwfJfTscunYd542aQuXqQU_RZ9kyt11ZFIM9rR3btJ9qaorOGQuR7c9mWSznyzXMF7hcLeBusTB6P9usq_ntrDKrm9kc5PF4_AMJE56Z">live editor</a>]
|
||||
|
||||
```
|
||||
sequenceDiagram
|
||||
Alice->>John: Hello John, how are you?
|
||||
loop Healthcheck
|
||||
loop HealthCheck
|
||||
John->>John: Fight against hypochondria
|
||||
end
|
||||
Note right of John: Rational thoughts!
|
||||
@ -132,7 +132,7 @@ Bob-->>John: Jolly good!
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
Alice->>John: Hello John, how are you?
|
||||
loop Healthcheck
|
||||
loop HealthCheck
|
||||
John->>John: Fight against hypochondria
|
||||
end
|
||||
Note right of John: Rational thoughts!
|
||||
@ -141,7 +141,7 @@ John->>Bob: How about you?
|
||||
Bob-->>John: Jolly good!
|
||||
```
|
||||
|
||||
### Gantt chart [<a href="https://mermaid-js.github.io/mermaid/#/gantt">docs</a> - <a href="https://mermaid.live/edit#pako:eNp90cGOgyAQBuBXIZxtFbG29bbZ3fsmvXKZylhJEAyOTZrGd1_sto3xsHMBhu-HBO689hp5xS_giJQbsCbjHTv9jcp9-q63SKhZpb3DhMXSOIiE5ZkoNpnYZGXynh6U-4jBK7JnVfBYJo9QvgjtEya1cj8QwFq0TMz4lZqxTBg0hOF5m1jifI2Lf7Bc490CyxUu1rhc4GLGPOEdhg6Mjq92V44xxanFDhWv4lRjA6MlxZWbIh17DYTf2pAPvGrADphwGMmfbq7mFYURX-jLwCVA91bWg8YYunO69Y8vMgPFI2vvGnOZ-2Owsd0S9UOVpvP29mKoHc_b2nfpYHQLgdrrsUzLvDxALrHcS9hJqeuzOB6avBCN3mciBz5N0y_wxZ0J">live editor</a>]
|
||||
### Gantt chart [<a href="https://mermaid.js.org/syntax/gantt.html">docs</a> - <a href="https://mermaid.live/edit#pako:eNp90cGOgyAQBuBXIZxtFbG29bbZ3fsmvXKZylhJEAyOTZrGd1_sto3xsHMBhu-HBO689hp5xS_giJQbsCbjHTv9jcp9-q63SKhZpb3DhMXSOIiE5ZkoNpnYZGXynh6U-4jBK7JnVfBYJo9QvgjtEya1cj8QwFq0TMz4lZqxTBg0hOF5m1jifI2Lf7Bc490CyxUu1rhc4GLGPOEdhg6Mjq92V44xxanFDhWv4lRjA6MlxZWbIh17DYTf2pAPvGrADphwGMmfbq7mFYURX-jLwCVA91bWg8YYunO69Y8vMgPFI2vvGnOZ-2Owsd0S9UOVpvP29mKoHc_b2nfpYHQLgdrrsUzLvDxALrHcS9hJqeuzOB6avBCN3mciBz5N0y_wxZ0J">live editor</a>]
|
||||
|
||||
```
|
||||
gantt
|
||||
@ -165,7 +165,7 @@ gantt
|
||||
Parallel 4 : des6, after des4, 1d
|
||||
```
|
||||
|
||||
### Class diagram [<a href="https://mermaid-js.github.io/mermaid/#/classDiagram">docs</a> - <a href="https://mermaid.live/edit#pako:eNpdkTFPwzAQhf-K5QlQ2zQJJG1UBaGWDYmBgYEwXO1LYuTEwXYqlZL_jt02asXm--690zvfgTLFkWaUSTBmI6DS0BTt2lfzkKx-p1PytEO9f1FtdaQkI2ulZNGuVqK1qEtgmOfk7BitSzKdOhg59XuNGgk0RDxed-_IOr6uf8cZ6UhTZ8bvHqS5ub1mr9svZPbjk6DEBlu7AQuXyBkx4gcvDk9cUMJq0XT_YaW0kNK5j-ufAoRzcihaQvLcoN4Jv50vvVxw_xrnD3RCG9QNCO4-8OgpqK1dpoJm7smxhF7agp6kfcfB4jMXVmmalW4tnFDorXrbt4xmVvc4is53GKFUwNF5DtTuO3-sShjrJjLVlqLyvNfS4drazmRB4NuzSti6386YagIjeA3a1rtlEiRRsoAoxiSN4SGOOduGy0UZ3YclT-dhBHQYhj8dc6_I">live editor</a>]
|
||||
### Class diagram [<a href="https://mermaid.js.org/syntax/classDiagram.html">docs</a> - <a href="https://mermaid.live/edit#pako:eNpdkTFPwzAQhf-K5QlQ2zQJJG1UBaGWDYmBgYEwXO1LYuTEwXYqlZL_jt02asXm--690zvfgTLFkWaUSTBmI6DS0BTt2lfzkKx-p1PytEO9f1FtdaQkI2ulZNGuVqK1qEtgmOfk7BitSzKdOhg59XuNGgk0RDxed-_IOr6uf8cZ6UhTZ8bvHqS5ub1mr9svZPbjk6DEBlu7AQuXyBkx4gcvDk9cUMJq0XT_YaW0kNK5j-ufAoRzcihaQvLcoN4Jv50vvVxw_xrnD3RCG9QNCO4-8OgpqK1dpoJm7smxhF7agp6kfcfB4jMXVmmalW4tnFDorXrbt4xmVvc4is53GKFUwNF5DtTuO3-sShjrJjLVlqLyvNfS4drazmRB4NuzSti6386YagIjeA3a1rtlEiRRsoAoxiSN4SGOOduGy0UZ3YclT-dhBHQYhj8dc6_I">live editor</a>]
|
||||
|
||||
```
|
||||
classDiagram
|
||||
@ -207,7 +207,7 @@ class Class10 {
|
||||
|
||||
```
|
||||
|
||||
### State diagram [<a href="https://mermaid-js.github.io/mermaid/#/stateDiagram">docs</a> - <a href="https://mermaid.live/edit#pako:eNpdkEFvgzAMhf8K8nEqpYSNthx22Xbcqcexg0sCiZQQlDhIFeK_L8A6TfXp6fOz9ewJGssFVOAJSbwr7ByadGR1n8T6evpO0vQ1uZDSekOrXGFsPqJPO6q-2-imH8f_0TeHXm50lfelsAMjnEHFY6xpMdRAUhhRQxUlFy0GTTXU_RytYeAx-AdXZB1ULWovdoCB7OXWN1CRC-Ju-r3uz6UtchGHJqDbsPygU57iysb2reoWHpyOWBINvsqypb3vFMlw3TfWZF5xiY7keC6zkpUnZIUojwW-FAVvrvn51LLnvOXHQ84Q5nn-AVtLcwk">live editor</a>]
|
||||
### State diagram [<a href="https://mermaid.js.org/syntax/stateDiagram.html">docs</a> - <a href="https://mermaid.live/edit#pako:eNpdkEFvgzAMhf8K8nEqpYSNthx22Xbcqcexg0sCiZQQlDhIFeK_L8A6TfXp6fOz9ewJGssFVOAJSbwr7ByadGR1n8T6evpO0vQ1uZDSekOrXGFsPqJPO6q-2-imH8f_0TeHXm50lfelsAMjnEHFY6xpMdRAUhhRQxUlFy0GTTXU_RytYeAx-AdXZB1ULWovdoCB7OXWN1CRC-Ju-r3uz6UtchGHJqDbsPygU57iysb2reoWHpyOWBINvsqypb3vFMlw3TfWZF5xiY7keC6zkpUnZIUojwW-FAVvrvn51LLnvOXHQ84Q5nn-AVtLcwk">live editor</a>]
|
||||
|
||||
```
|
||||
stateDiagram-v2
|
||||
@ -229,7 +229,7 @@ Moving --> Crash
|
||||
Crash --> [*]
|
||||
```
|
||||
|
||||
### Pie chart [<a href="https://mermaid-js.github.io/mermaid/#/pie">docs</a> - <a href="https://mermaid.live/edit#pako:eNo9jsFugzAMhl8F-VzBgEEh13Uv0F1zcYkTIpEEBadShXj3BU3dzf_n77e8wxQUgYDVkvQSbsFsEgpRtEN_5i_kvzx05XiC-xvUHVzAUXRoVe7v0heFBJ7JkQSRR0Ua08ISpD-ymlaFTN_KcoggNC4bXQATh5-Xn0BwTPSWbhZNRPdvLQEV5dIO_FrPZ43dOJ-cgtfWnDzFJeOZed1EVZ3r0lie06Ocgqs2q2aMPD_HvuqbfsCmpf7aYte2anrU46Cbz1qr60fdIBzH8QvW9lkl">live editor</a>]
|
||||
### Pie chart [<a href="https://mermaid.js.org/syntax/pie.html">docs</a> - <a href="https://mermaid.live/edit#pako:eNo9jsFugzAMhl8F-VzBgEEh13Uv0F1zcYkTIpEEBadShXj3BU3dzf_n77e8wxQUgYDVkvQSbsFsEgpRtEN_5i_kvzx05XiC-xvUHVzAUXRoVe7v0heFBJ7JkQSRR0Ua08ISpD-ymlaFTN_KcoggNC4bXQATh5-Xn0BwTPSWbhZNRPdvLQEV5dIO_FrPZ43dOJ-cgtfWnDzFJeOZed1EVZ3r0lie06Ocgqs2q2aMPD_HvuqbfsCmpf7aYte2anrU46Cbz1qr60fdIBzH8QvW9lkl">live editor</a>]
|
||||
|
||||
```
|
||||
pie
|
||||
@ -247,7 +247,7 @@ pie
|
||||
|
||||
### Git graph [experimental - <a href="https://mermaid.live/edit#pako:eNqNkMFugzAMhl8F-VyVAR1tOW_aA-zKxSSGRCMJCk6lCvHuNZPKZdM0n-zf3_8r8QIqaIIGMqnB8kfEybQ--y4VnLP8-9RF9Mpkmm40hmlnDKmvkPiH_kfS7nFo_VN0FAf6XwocQGgxa_nGsm1bYEOOWmik1dRjGrmF1q-Cpkkj07u2HCI0PY4zHQATh8-7V9BwTPSE3iwOEd1OjQE1iWkBvk_bzQY7s0Sq4Hs7bHqKo8iGeZqbPN_WR7mpSd1RHpvPVhuMbG7XOq_L-oJlRfW5wteq0qorrpe-PBW9Pr8UJcK6rg-BLYPQ">live editor</a>]
|
||||
|
||||
### Bar chart (using gantt chart) [<a href="https://mermaid-js.github.io/mermaid/#/gantt">docs</a> - <a href="https://mermaid.live/edit#pako:eNptkU1vhCAQhv8KIenNugiI4rkf6bmXpvEyFVxJFDYyNt1u9r8X63Z7WQ9m5pknLzieaBeMpQ3dg0dsPUkPOhwteXZIXmJcbCT3xMAxkuh8Z8kIEclyMIB209fqKcwTICFvG4IvFy_oLrZ-g9F26ILfQgvNFN94VaRXQ1iWqpumZBcu1J8p1E1TXDx59eQNr5LyEqjJn6hv5QnGNlxevZJmdLLpy5xJSzut45biYCfb0iaVxvawjNjS1p-TCguG16PvaIPzYjO67e3BwX6GiTY9jPFKH43DMF_hGMDY1J4oHg-_f8hFTJFd8L3br3yZx4QHxENsdrt1nO8dDstH3oVpF50ZYMbhU6ud4qoGLqyqBJRCmO6j0HXPZdGbihUc6Pmc0QP49xD-b5X69ZQv2gjO81IwzWqhC1lKrjJ6pA3nVS7SMiVjrKirWlYp5fs3osgrWeo00lorLWvOzz8JVbXm">live editor</a>]
|
||||
### Bar chart (using gantt chart) [<a href="https://mermaid.js.org/syntax/gantt.html">docs</a> - <a href="https://mermaid.live/edit#pako:eNptkU1vhCAQhv8KIenNugiI4rkf6bmXpvEyFVxJFDYyNt1u9r8X63Z7WQ9m5pknLzieaBeMpQ3dg0dsPUkPOhwteXZIXmJcbCT3xMAxkuh8Z8kIEclyMIB209fqKcwTICFvG4IvFy_oLrZ-g9F26ILfQgvNFN94VaRXQ1iWqpumZBcu1J8p1E1TXDx59eQNr5LyEqjJn6hv5QnGNlxevZJmdLLpy5xJSzut45biYCfb0iaVxvawjNjS1p-TCguG16PvaIPzYjO67e3BwX6GiTY9jPFKH43DMF_hGMDY1J4oHg-_f8hFTJFd8L3br3yZx4QHxENsdrt1nO8dDstH3oVpF50ZYMbhU6ud4qoGLqyqBJRCmO6j0HXPZdGbihUc6Pmc0QP49xD-b5X69ZQv2gjO81IwzWqhC1lKrjJ6pA3nVS7SMiVjrKirWlYp5fs3osgrWeo00lorLWvOzz8JVbXm">live editor</a>]
|
||||
|
||||
```
|
||||
gantt
|
||||
@ -285,7 +285,7 @@ gantt
|
||||
5 : 0, 5
|
||||
```
|
||||
|
||||
### User Journey diagram [<a href="https://mermaid-js.github.io/mermaid/#/user-journey">docs</a> - <a href="https://mermaid.live/edit#pako:eNplkMFuwjAQRH9l5TMiTVIC-FqqnjhxzWWJN4khsSN7XRSh_HsdKBVt97R6Mzsj-yoqq0hIAXCywRkaSwNxWHNHsB_hYt1ZmwYUfiueKtbWwIcFtjf5zgH2eCZgQgkrCXt64GgMg2fUzkvIn5Xd_V5COtMFvCH_62ht_5yk7MU8sn61HDTfxD8VYiF6cj1qFd94nWkpuKWYKWRcFdUYOi5FaaZoDYNCpnel2Toha-w8LQQGtofRVEKyC_Qw7TQ2DvsfV2dRUTy6Ch6H-UMb7TlGVtbUupl5cF3ELfPgZZLM8rLR3IbjsrJ94rVq0XH7uS2SIis2mOVUrHNc5bmqjul2U2evaa3WL2mGYpqmL2BGiho">live editor</a>]
|
||||
### User Journey diagram [<a href="https://mermaid.js.org/syntax/userJourney.html">docs</a> - <a href="https://mermaid.live/edit#pako:eNplkMFuwjAQRH9l5TMiTVIC-FqqnjhxzWWJN4khsSN7XRSh_HsdKBVt97R6Mzsj-yoqq0hIAXCywRkaSwNxWHNHsB_hYt1ZmwYUfiueKtbWwIcFtjf5zgH2eCZgQgkrCXt64GgMg2fUzkvIn5Xd_V5COtMFvCH_62ht_5yk7MU8sn61HDTfxD8VYiF6cj1qFd94nWkpuKWYKWRcFdUYOi5FaaZoDYNCpnel2Toha-w8LQQGtofRVEKyC_Qw7TQ2DvsfV2dRUTy6Ch6H-UMb7TlGVtbUupl5cF3ELfPgZZLM8rLR3IbjsrJ94rVq0XH7uS2SIis2mOVUrHNc5bmqjul2U2evaa3WL2mGYpqmL2BGiho">live editor</a>]
|
||||
|
||||
```
|
||||
journey
|
||||
@ -311,7 +311,7 @@ gantt
|
||||
Sit down: 3: Me
|
||||
```
|
||||
|
||||
### C4 diagram [<a href="https://mermaid-js.github.io/mermaid/#/c4c">docs</a>]
|
||||
### C4 diagram [<a href="https://mermaid.js.org/syntax/c4.html">docs</a>]
|
||||
|
||||
```
|
||||
C4Context
|
||||
@ -405,7 +405,7 @@ The above command generates files into the `dist` folder and publishes them to <
|
||||
|
||||
Mermaid is a growing community and is always accepting new contributors. There's a lot of different ways to help out and we're always looking for extra hands! Look at [this issue](https://github.com/mermaid-js/mermaid/issues/866) if you want to know where to start helping out.
|
||||
|
||||
Detailed information about how to contribute can be found in the [contribution guide](CONTRIBUTING.md)
|
||||
Detailed information about how to contribute can be found in the [contribution guide](https://mermaid.js.org/community/contributing.html)
|
||||
|
||||
## Security and safe diagrams
|
||||
|
||||
|
@ -15,7 +15,7 @@ Mermaid
|
||||
<a href="https://mermaid.live/"><b>实时编辑器!</b></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://mermaid.js.org">📖 文档</a> | <a href="https://mermaid.js.org/intro/">🚀 入门</a> | <a href="https://www.jsdelivr.com/package/npm/mermaid">🌐 CDN</a> | <a href="https://discord.gg/wwtabKgp8y" title="Discord invite">🙌 加入我们</a>
|
||||
<a href="https://mermaid.js.org">📖 文档</a> | <a href="https://mermaid.js.org/intro/">🚀 入门</a> | <a href="https://www.jsdelivr.com/package/npm/mermaid">🌐 CDN</a> | <a href="https://discord.gg/AgrbSrBer3" title="Discord invite">🙌 加入我们</a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="./README.md">English</a>
|
||||
@ -34,7 +34,7 @@ Mermaid
|
||||
[![Coverage Status](https://codecov.io/github/mermaid-js/mermaid/branch/develop/graph/badge.svg)](https://app.codecov.io/github/mermaid-js/mermaid/tree/develop)
|
||||
[![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid)
|
||||
[![NPM Downloads](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid)
|
||||
[![Join our Discord!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=discord&label=discord)](https://discord.gg/wwtabKgp8y)
|
||||
[![Join our Discord!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=discord&label=discord)](https://discord.gg/AgrbSrBer3)
|
||||
[![Twitter Follow](https://img.shields.io/badge/Social-mermaidjs__-blue?style=social&logo=X)](https://twitter.com/mermaidjs_)
|
||||
|
||||
<img src="./img/header.png" alt="" />
|
||||
@ -43,7 +43,7 @@ Mermaid
|
||||
|
||||
**感谢所有参与进来提交 PR,解答疑问的人们! 🙏**
|
||||
|
||||
<a href="https://mermaid-js.github.io/mermaid/landing/"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/intro/img/book-banner-post-release.jpg" alt="Explore Mermaid.js in depth, with real-world examples, tips & tricks from the creator... The first official book on Mermaid is available for purchase. Check it out!"></a>
|
||||
<a href="https://mermaid.js.org/landing/"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/intro/img/book-banner-post-release.jpg" alt="Explore Mermaid.js in depth, with real-world examples, tips & tricks from the creator... The first official book on Mermaid is available for purchase. Check it out!"></a>
|
||||
|
||||
## 关于 Mermaid
|
||||
|
||||
@ -57,20 +57,20 @@ Mermaid 是一个基于 Javascript 的图表绘制工具,通过解析类 Markd
|
||||
Mermaid 通过允许用户创建便于修改的图表来解决这一难题,它也可以作为生产脚本(或其他代码)的一部分。<br/>
|
||||
<br/>
|
||||
Mermaid 甚至能让非程序员也能通过 [Mermaid Live Editor](https://mermaid.live/) 轻松创建详细的图表。<br/>
|
||||
你可以访问 [教程](./docs/ecosystem/tutorials.md) 来查看 Live Editor 的视频教程,也可以查看 [Mermaid 的集成和使用](./docs/ecosystem/integrations-community.md) 这个清单来检查你的文档工具是否已经集成了 Mermaid 支持。
|
||||
你可以访问 [教程](https://mermaid.js.org/ecosystem/tutorials.html) 来查看 Live Editor 的视频教程,也可以查看 [Mermaid 的集成和使用](https://mermaid.js.org/ecosystem/integrations-community.html) 这个清单来检查你的文档工具是否已经集成了 Mermaid 支持。
|
||||
|
||||
如果想要查看关于 Mermaid 更详细的介绍及基础使用方式,可以查看 [入门指引](./docs/intro/getting-started.md), [用法](./docs/config/usage.md) 和 [教程](./docs/ecosystem/tutorials.md).
|
||||
如果想要查看关于 Mermaid 更详细的介绍及基础使用方式,可以查看 [入门指引](https://mermaid.js.org/intro/getting-started.html), [用法](https://mermaid.js.org/config/usage.html) 和 [教程](https://mermaid.js.org/ecosystem/tutorials.html).
|
||||
|
||||
<!-- </Main description> -->
|
||||
|
||||
## 示例
|
||||
|
||||
**下面是一些可以使用 Mermaid 创建的图表示例。点击 [语法](https://mermaid-js.github.io/mermaid/#/n00b-syntaxReference) 查看详情。**
|
||||
**下面是一些可以使用 Mermaid 创建的图表示例。点击 [语法](https://mermaid.js.org/intro/syntax-reference.html) 查看详情。**
|
||||
|
||||
<table>
|
||||
<!-- <Flowchart> -->
|
||||
|
||||
### 流程图 [<a href="https://mermaid-js.github.io/mermaid/#/flowchart">文档</a> - <a href="https://mermaid.live/edit#base64:eyJjb2RlIjoiZ3JhcGggVERcbiAgICBBW0hhcmRdIC0tPnxUZXh0fCBCKFJvdW5kKVxuICAgIEIgLS0-IEN7RGVjaXNpb259XG4gICAgQyAtLT58T25lfCBEW1Jlc3VsdCAxXVxuICAgIEMgLS0-fFR3b3wgRVtSZXN1bHQgMl0iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
|
||||
### 流程图 [<a href="https://mermaid.js.org/syntax/flowchart.html">文档</a> - <a href="https://mermaid.live/edit#base64:eyJjb2RlIjoiZ3JhcGggVERcbiAgICBBW0hhcmRdIC0tPnxUZXh0fCBCKFJvdW5kKVxuICAgIEIgLS0-IEN7RGVjaXNpb259XG4gICAgQyAtLT58T25lfCBEW1Jlc3VsdCAxXVxuICAgIEMgLS0-fFR3b3wgRVtSZXN1bHQgMl0iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
|
||||
|
||||
```
|
||||
flowchart LR
|
||||
@ -88,12 +88,12 @@ C -->|One| D[Result 1]
|
||||
C -->|Two| E[Result 2]
|
||||
```
|
||||
|
||||
### 时序图 [<a href="https://mermaid-js.github.io/mermaid/#/sequenceDiagram">文档</a> - <a href="https://mermaid.live/edit#base64:eyJjb2RlIjoic2VxdWVuY2VEaWFncmFtXG5BbGljZS0-PkpvaG46IEhlbGxvIEpvaG4sIGhvdyBhcmUgeW91P1xubG9vcCBIZWFsdGhjaGVja1xuICAgIEpvaG4tPj5Kb2huOiBGaWdodCBhZ2FpbnN0IGh5cG9jaG9uZHJpYVxuZW5kXG5Ob3RlIHJpZ2h0IG9mIEpvaG46IFJhdGlvbmFsIHRob3VnaHRzIVxuSm9obi0tPj5BbGljZTogR3JlYXQhXG5Kb2huLT4-Qm9iOiBIb3cgYWJvdXQgeW91P1xuQm9iLS0-PkpvaG46IEpvbGx5IGdvb2QhIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
|
||||
### 时序图 [<a href="https://mermaid.js.org/syntax/sequenceDiagram.html">文档</a> - <a href="https://mermaid.live/edit#base64:eyJjb2RlIjoic2VxdWVuY2VEaWFncmFtXG5BbGljZS0-PkpvaG46IEhlbGxvIEpvaG4sIGhvdyBhcmUgeW91P1xubG9vcCBIZWFsdGhjaGVja1xuICAgIEpvaG4tPj5Kb2huOiBGaWdodCBhZ2FpbnN0IGh5cG9jaG9uZHJpYVxuZW5kXG5Ob3RlIHJpZ2h0IG9mIEpvaG46IFJhdGlvbmFsIHRob3VnaHRzIVxuSm9obi0tPj5BbGljZTogR3JlYXQhXG5Kb2huLT4-Qm9iOiBIb3cgYWJvdXQgeW91P1xuQm9iLS0-PkpvaG46IEpvbGx5IGdvb2QhIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
|
||||
|
||||
```
|
||||
sequenceDiagram
|
||||
Alice->>John: Hello John, how are you?
|
||||
loop Healthcheck
|
||||
loop HealthCheck
|
||||
John->>John: Fight against hypochondria
|
||||
end
|
||||
Note right of John: Rational thoughts!
|
||||
@ -105,7 +105,7 @@ Bob-->>John: Jolly good!
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
Alice->>John: Hello John, how are you?
|
||||
loop Healthcheck
|
||||
loop HealthCheck
|
||||
John->>John: Fight against hypochondria
|
||||
end
|
||||
Note right of John: Rational thoughts!
|
||||
@ -114,7 +114,7 @@ John->>Bob: How about you?
|
||||
Bob-->>John: Jolly good!
|
||||
```
|
||||
|
||||
### 甘特图 [<a href="https://mermaid-js.github.io/mermaid/#/gantt">文档</a> - <a href="https://mermaid.live/edit#base64:eyJjb2RlIjoiZ2FudHRcbnNlY3Rpb24gU2VjdGlvblxuQ29tcGxldGVkIDpkb25lLCAgICBkZXMxLCAyMDE0LTAxLTA2LDIwMTQtMDEtMDhcbkFjdGl2ZSAgICAgICAgOmFjdGl2ZSwgIGRlczIsIDIwMTQtMDEtMDcsIDNkXG5QYXJhbGxlbCAxICAgOiAgICAgICAgIGRlczMsIGFmdGVyIGRlczEsIDFkXG5QYXJhbGxlbCAyICAgOiAgICAgICAgIGRlczQsIGFmdGVyIGRlczEsIDFkXG5QYXJhbGxlbCAzICAgOiAgICAgICAgIGRlczUsIGFmdGVyIGRlczMsIDFkXG5QYXJhbGxlbCA0ICAgOiAgICAgICAgIGRlczYsIGFmdGVyIGRlczQsIDFkIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
|
||||
### 甘特图 [<a href="https://mermaid.js.org/syntax/gantt.html">文档</a> - <a href="https://mermaid.live/edit#base64:eyJjb2RlIjoiZ2FudHRcbnNlY3Rpb24gU2VjdGlvblxuQ29tcGxldGVkIDpkb25lLCAgICBkZXMxLCAyMDE0LTAxLTA2LDIwMTQtMDEtMDhcbkFjdGl2ZSAgICAgICAgOmFjdGl2ZSwgIGRlczIsIDIwMTQtMDEtMDcsIDNkXG5QYXJhbGxlbCAxICAgOiAgICAgICAgIGRlczMsIGFmdGVyIGRlczEsIDFkXG5QYXJhbGxlbCAyICAgOiAgICAgICAgIGRlczQsIGFmdGVyIGRlczEsIDFkXG5QYXJhbGxlbCAzICAgOiAgICAgICAgIGRlczUsIGFmdGVyIGRlczMsIDFkXG5QYXJhbGxlbCA0ICAgOiAgICAgICAgIGRlczYsIGFmdGVyIGRlczQsIDFkIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
|
||||
|
||||
```
|
||||
gantt
|
||||
@ -138,7 +138,7 @@ gantt
|
||||
Parallel 4 : des6, after des4, 1d
|
||||
```
|
||||
|
||||
### 类图 [<a href="https://mermaid-js.github.io/mermaid/#/classDiagram">文档</a> - <a href="https://mermaid.live/edit#base64:eyJjb2RlIjoiY2xhc3NEaWFncmFtXG5DbGFzczAxIDx8LS0gQXZlcnlMb25nQ2xhc3MgOiBDb29sXG48PGludGVyZmFjZT4-IENsYXNzMDFcbkNsYXNzMDkgLS0-IEMyIDogV2hlcmUgYW0gaT9cbkNsYXNzMDkgLS0qIEMzXG5DbGFzczA5IC0tfD4gQ2xhc3MwN1xuQ2xhc3MwNyA6IGVxdWFscygpXG5DbGFzczA3IDogT2JqZWN0W10gZWxlbWVudERhdGFcbkNsYXNzMDEgOiBzaXplKClcbkNsYXNzMDEgOiBpbnQgY2hpbXBcbkNsYXNzMDEgOiBpbnQgZ29yaWxsYVxuY2xhc3MgQ2xhc3MxMCB7XG4gID4-c2VydmljZT4-XG4gIGludCBpZFxuICBzaXplKClcbn0iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
|
||||
### 类图 [<a href="https://mermaid.js.org/syntax/classDiagram.html">文档</a> - <a href="https://mermaid.live/edit#base64:eyJjb2RlIjoiY2xhc3NEaWFncmFtXG5DbGFzczAxIDx8LS0gQXZlcnlMb25nQ2xhc3MgOiBDb29sXG48PGludGVyZmFjZT4-IENsYXNzMDFcbkNsYXNzMDkgLS0-IEMyIDogV2hlcmUgYW0gaT9cbkNsYXNzMDkgLS0qIEMzXG5DbGFzczA5IC0tfD4gQ2xhc3MwN1xuQ2xhc3MwNyA6IGVxdWFscygpXG5DbGFzczA3IDogT2JqZWN0W10gZWxlbWVudERhdGFcbkNsYXNzMDEgOiBzaXplKClcbkNsYXNzMDEgOiBpbnQgY2hpbXBcbkNsYXNzMDEgOiBpbnQgZ29yaWxsYVxuY2xhc3MgQ2xhc3MxMCB7XG4gID4-c2VydmljZT4-XG4gIGludCBpZFxuICBzaXplKClcbn0iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
|
||||
|
||||
```
|
||||
classDiagram
|
||||
@ -178,7 +178,7 @@ class Class10 {
|
||||
}
|
||||
```
|
||||
|
||||
### 状态图 [[<a href="https://mermaid-js.github.io/mermaid/#/stateDiagram">docs</a> - <a href="https://mermaid.live/edit#pako:eNpdkLsOwjAMRX-l8ojahTEDCzB26kgYrMYtkfJAqVMJVf13QiIKqqfr44d8vUDvFYGAiZHponEMaJv5KF2V4na4V01zqjrWxhSUZYapuEetn7UbCy16P_5HzwGnR6FZfpdCDZaCRa3SWcunQQI_yJIEkaSiAaNhCdKtqRUj--7lehAcItUQn-pnBMSAZtroVWn2YYOU07b4z29Y37gJVYk">live editor</a>]
|
||||
### 状态图 [<a href="https://mermaid.js.org/syntax/stateDiagram.html">docs</a> - <a href="https://mermaid.live/edit#pako:eNpdkLsOwjAMRX-l8ojahTEDCzB26kgYrMYtkfJAqVMJVf13QiIKqqfr44d8vUDvFYGAiZHponEMaJv5KF2V4na4V01zqjrWxhSUZYapuEetn7UbCy16P_5HzwGnR6FZfpdCDZaCRa3SWcunQQI_yJIEkaSiAaNhCdKtqRUj--7lehAcItUQn-pnBMSAZtroVWn2YYOU07b4z29Y37gJVYk">live editor</a>]
|
||||
|
||||
```
|
||||
stateDiagram-v2
|
||||
@ -200,7 +200,7 @@ Moving --> Crash
|
||||
Crash --> [*]
|
||||
```
|
||||
|
||||
### 饼图 [<a href="https://mermaid-js.github.io/mermaid/#/pie">文档</a> - <a href="https://mermaid.live/edit#base64:eyJjb2RlIjoicGllXG5cIkRvZ3NcIiA6IDQyLjk2XG5cIkNhdHNcIiA6IDUwLjA1XG5cIlJhdHNcIiA6IDEwLjAxIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
|
||||
### 饼图 [<a href="https://mermaid.js.org/syntax/pie.html">文档</a> - <a href="https://mermaid.live/edit#base64:eyJjb2RlIjoicGllXG5cIkRvZ3NcIiA6IDQyLjk2XG5cIkNhdHNcIiA6IDUwLjA1XG5cIlJhdHNcIiA6IDEwLjAxIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
|
||||
|
||||
```
|
||||
pie
|
||||
@ -218,7 +218,7 @@ pie
|
||||
|
||||
### Git 图 [实验特性 - <a href="https://mermaid.live/edit#base64:eyJjb2RlIjoiZ2l0R3JhcGg6XG5vcHRpb25zXG57XG4gICAgXCJub2RlU3BhY2luZ1wiOiAxNTAsXG4gICAgXCJub2RlUmFkaXVzXCI6IDEwXG59XG5lbmRcbmNvbW1pdFxuYnJhbmNoIG5ld2JyYW5jaFxuY2hlY2tvdXQgbmV3YnJhbmNoXG5jb21taXRcbmNvbW1pdFxuY2hlY2tvdXQgbWFzdGVyXG5jb21taXRcbmNvbW1pdFxubWVyZ2UgbmV3YnJhbmNoXG4iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
|
||||
|
||||
### 用户体验旅程图 [<a href="https://mermaid-js.github.io/mermaid/#/user-journey">文档</a> - <a href="https://mermaid.live/edit#pako:eNpljzEPgkAMhf9K05nFGJdbJXFiYmVpuKIncDVHL4QQ_ruHaILaqXnf63vpjLVYRoMAd4nB81R5SKNOO4ZiglFC6_wVLL3JwLU68XARUHnhTQcoqGVQJgMnAwV_5GSMj0HJhcHAcU_y7d7AYVUzOJP-ddyk3ydZGf0n66uldPqCPxWYYc-hJ2fTj_OqVqg3Tplo0mq5odhphZVfkpWiSjn5Go2GyBnGhyXl3NE1UI-moW7g5QkSoF5m">live editor</a>]
|
||||
### 用户体验旅程图 [<a href="https://mermaid.js.org/syntax/userJourney.html">文档</a> - <a href="https://mermaid.live/edit#pako:eNpljzEPgkAMhf9K05nFGJdbJXFiYmVpuKIncDVHL4QQ_ruHaILaqXnf63vpjLVYRoMAd4nB81R5SKNOO4ZiglFC6_wVLL3JwLU68XARUHnhTQcoqGVQJgMnAwV_5GSMj0HJhcHAcU_y7d7AYVUzOJP-ddyk3ydZGf0n66uldPqCPxWYYc-hJ2fTj_OqVqg3Tplo0mq5odhphZVfkpWiSjn5Go2GyBnGhyXl3NE1UI-moW7g5QkSoF5m">live editor</a>]
|
||||
|
||||
```
|
||||
journey
|
||||
@ -244,7 +244,7 @@ pie
|
||||
Sit down: 3: Me
|
||||
```
|
||||
|
||||
### C4 图 [<a href="https://mermaid-js.github.io/mermaid/#/c4c">文档</a>]
|
||||
### C4 图 [<a href="https://mermaid.js.org/syntax/c4.html">文档</a>]
|
||||
|
||||
```
|
||||
C4Context
|
||||
@ -338,7 +338,7 @@ npm publish
|
||||
|
||||
Mermaid 是一个不断发展中的社区,并且还在接收新的贡献者。有很多不同的方式可以参与进来,而且我们还在寻找额外的帮助。如果你想知道如何开始贡献,请查看 [这个 issue](https://github.com/mermaid-js/mermaid/issues/866)。
|
||||
|
||||
关于如何贡献的详细信息可以在 [贡献指南](CONTRIBUTING.md) 中找到。
|
||||
关于如何贡献的详细信息可以在 [贡献指南](https://mermaid.js.org/community/contributing.html) 中找到。
|
||||
|
||||
## 安全
|
||||
|
||||
|
209
cSpell.json
209
cSpell.json
@ -1,209 +0,0 @@
|
||||
{
|
||||
"version": "0.2",
|
||||
"language": "en",
|
||||
"words": [
|
||||
"acyclicer",
|
||||
"adamiecki",
|
||||
"alois",
|
||||
"aloisklink",
|
||||
"antiscript",
|
||||
"antlr",
|
||||
"appli",
|
||||
"applitools",
|
||||
"asciidoctor",
|
||||
"ashish",
|
||||
"ashishjain",
|
||||
"astah",
|
||||
"bbox",
|
||||
"bilkent",
|
||||
"bisheng",
|
||||
"blrs",
|
||||
"braintree",
|
||||
"brkt",
|
||||
"brolin",
|
||||
"brotli",
|
||||
"catmull",
|
||||
"città",
|
||||
"classdef",
|
||||
"codedoc",
|
||||
"codemia",
|
||||
"colour",
|
||||
"commitlint",
|
||||
"cpettitt",
|
||||
"customizability",
|
||||
"cuzon",
|
||||
"cytoscape",
|
||||
"dagre",
|
||||
"deepdwn",
|
||||
"descr",
|
||||
"docsify",
|
||||
"docsy",
|
||||
"doku",
|
||||
"dompurify",
|
||||
"dont",
|
||||
"doublecircle",
|
||||
"edgechromium",
|
||||
"elems",
|
||||
"elkjs",
|
||||
"elle",
|
||||
"faber",
|
||||
"flatmap",
|
||||
"foswiki",
|
||||
"frontmatter",
|
||||
"ftplugin",
|
||||
"gantt",
|
||||
"gitea",
|
||||
"gitgraph",
|
||||
"globby",
|
||||
"graphlib",
|
||||
"graphviz",
|
||||
"grav",
|
||||
"greywolf",
|
||||
"gzipped",
|
||||
"huynh",
|
||||
"huynhicode",
|
||||
"inkdrop",
|
||||
"jaoude",
|
||||
"jgreywolf",
|
||||
"jison",
|
||||
"jiti",
|
||||
"kaufmann",
|
||||
"khroma",
|
||||
"klemm",
|
||||
"klink",
|
||||
"knsv",
|
||||
"knut",
|
||||
"knutsveidqvist",
|
||||
"laganeckas",
|
||||
"linetype",
|
||||
"lintstagedrc",
|
||||
"logmsg",
|
||||
"lucida",
|
||||
"markdownish",
|
||||
"matthieu",
|
||||
"matthieumorel",
|
||||
"mdast",
|
||||
"mdbook",
|
||||
"mermaidjs",
|
||||
"mermerd",
|
||||
"mindaugas",
|
||||
"mindmap",
|
||||
"mindmaps",
|
||||
"mitigations",
|
||||
"mkdocs",
|
||||
"mmorel",
|
||||
"mult",
|
||||
"neurodiverse",
|
||||
"nextra",
|
||||
"nikolay",
|
||||
"nirname",
|
||||
"npmjs",
|
||||
"orlandoni",
|
||||
"pathe",
|
||||
"pbrolin",
|
||||
"phpbb",
|
||||
"pixelmatch",
|
||||
"plantuml",
|
||||
"playfair",
|
||||
"pnpm",
|
||||
"podlite",
|
||||
"quence",
|
||||
"radious",
|
||||
"ranksep",
|
||||
"rect",
|
||||
"rects",
|
||||
"reda",
|
||||
"redmine",
|
||||
"regexes",
|
||||
"rehype",
|
||||
"roledescription",
|
||||
"rozhkov",
|
||||
"sandboxed",
|
||||
"sankey",
|
||||
"setupgraphviewbox",
|
||||
"shiki",
|
||||
"sidharth",
|
||||
"sidharthv",
|
||||
"sphinxcontrib",
|
||||
"ssim",
|
||||
"startx",
|
||||
"starty",
|
||||
"statediagram",
|
||||
"steph",
|
||||
"stopx",
|
||||
"stopy",
|
||||
"stylis",
|
||||
"subhash-halder",
|
||||
"substate",
|
||||
"sulais",
|
||||
"sveidqvist",
|
||||
"swimm",
|
||||
"techn",
|
||||
"teststr",
|
||||
"textlength",
|
||||
"treemap",
|
||||
"ts-nocheck",
|
||||
"tsdoc",
|
||||
"tuleap",
|
||||
"tylerlong",
|
||||
"typora",
|
||||
"ugge",
|
||||
"unist",
|
||||
"unocss",
|
||||
"upvoting",
|
||||
"valign",
|
||||
"verdana",
|
||||
"viewports",
|
||||
"vinod",
|
||||
"visio",
|
||||
"vitepress",
|
||||
"vueuse",
|
||||
"xlink",
|
||||
"xychart",
|
||||
"yash",
|
||||
"yokozuna",
|
||||
"zenuml",
|
||||
"zune"
|
||||
],
|
||||
"patterns": [
|
||||
{ "name": "Markdown links", "pattern": "\\((.*)\\)", "description": "" },
|
||||
{
|
||||
"name": "Markdown code blocks",
|
||||
"pattern": "/^(\\s*`{3,}).*[\\s\\S]*?^\\1/gmx",
|
||||
"description": "Taken from the cSpell example at https://cspell.org/configuration/patterns/#verbose-regular-expressions"
|
||||
},
|
||||
{
|
||||
"name": "Inline code blocks",
|
||||
"pattern": "\\`([^\\`\\r\\n]+?)\\`",
|
||||
"description": "https://stackoverflow.com/questions/41274241/how-to-capture-inline-markdown-code-but-not-a-markdown-code-fence-with-regex"
|
||||
},
|
||||
{ "name": "Link contents", "pattern": "\\<a(.*)\\>", "description": "" },
|
||||
{ "name": "Snippet references", "pattern": "-- snippet:(.*)", "description": "" },
|
||||
{
|
||||
"name": "Snippet references 2",
|
||||
"pattern": "\\<\\[sample:(.*)",
|
||||
"description": "another kind of snippet reference"
|
||||
},
|
||||
{ "name": "Multi-line code blocks", "pattern": "/^\\s*```[\\s\\S]*?^\\s*```/gm" },
|
||||
{
|
||||
"name": "HTML Tags",
|
||||
"pattern": "<[^>]*>",
|
||||
"description": "Reference: https://stackoverflow.com/questions/11229831/regular-expression-to-remove-html-tags-from-a-string"
|
||||
}
|
||||
],
|
||||
"ignoreRegExpList": [
|
||||
"Markdown links",
|
||||
"Markdown code blocks",
|
||||
"Inline code blocks",
|
||||
"Link contents",
|
||||
"Snippet references",
|
||||
"Snippet references 2",
|
||||
"Multi-line code blocks",
|
||||
"HTML Tags"
|
||||
],
|
||||
"ignorePaths": [
|
||||
"packages/mermaid/src/docs/CHANGELOG.md",
|
||||
"packages/mermaid/src/docs/.vitepress/redirect.ts",
|
||||
"packages/mermaid/src/docs/.vitepress/contributor-names.json"
|
||||
]
|
||||
}
|
45
cspell.config.yaml
Normal file
45
cspell.config.yaml
Normal file
@ -0,0 +1,45 @@
|
||||
# yaml-language-server: $schema=https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json
|
||||
|
||||
$schema: https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json
|
||||
version: '0.2'
|
||||
language: en-US,en-GB
|
||||
|
||||
import:
|
||||
- ./.cspell/cspell.config.yaml
|
||||
|
||||
ignoreRegExpList:
|
||||
- character-set-cyrillic
|
||||
- svg-block
|
||||
ignorePaths:
|
||||
- '*lock.{yaml,json}'
|
||||
- dist
|
||||
- CHANGELOG.md
|
||||
- packages/mermaid/src/docs/.vitepress/redirect.ts
|
||||
- packages/mermaid/src/docs/.vitepress/contributor-names.json
|
||||
- backup
|
||||
- '**/*.spec.{js,ts}' # checked by eslint
|
||||
- 'tests/webpack/src/index.js' # checked by eslint
|
||||
- 'cypress/**/*.js' # checked by eslint
|
||||
- '*.csv'
|
||||
- '*.patch'
|
||||
- 'docs/**/*.html'
|
||||
- 'cypress/platform/**'
|
||||
dictionaries:
|
||||
- misc-terms
|
||||
overrides:
|
||||
- filename:
|
||||
- '**/*.{jison,ts,mts,cjs,mjs,js,json,yaml,yml,md,html}'
|
||||
- 'run'
|
||||
- Dockerfile
|
||||
ignoreRegExpList:
|
||||
- js-unicode-escape
|
||||
dictionaries:
|
||||
- code-terms
|
||||
- 3rd-party-terms
|
||||
- fonts
|
||||
- html
|
||||
- lorem-ipsum
|
||||
- filename: '**/package.json'
|
||||
ignoreRegExpList:
|
||||
- json-property
|
||||
# cspell:dictionaries code-terms
|
386
cypress/integration/rendering/block.spec.js
Normal file
386
cypress/integration/rendering/block.spec.js
Normal file
@ -0,0 +1,386 @@
|
||||
import { imgSnapshotTest } from '../../helpers/util';
|
||||
/* eslint-disable no-useless-escape */
|
||||
describe('Block diagram', () => {
|
||||
it('BL1: should calculate the block widths', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
columns 2
|
||||
block
|
||||
id2["I am a wide one"]
|
||||
id1
|
||||
end
|
||||
id["Next row"]
|
||||
`
|
||||
);
|
||||
});
|
||||
|
||||
it('BL2: should handle colums statement in sub-blocks', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
id1["Hello"]
|
||||
block
|
||||
columns 3
|
||||
id2["to"]
|
||||
id3["the"]
|
||||
id4["World"]
|
||||
id5["World"]
|
||||
end
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL3: should align block widths and handle colums statement in sub-blocks', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
block
|
||||
columns 1
|
||||
id1
|
||||
id2
|
||||
id2.1
|
||||
end
|
||||
id3
|
||||
id4
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL4: should align block widths and handle colums statements in deeper sub-blocks then 1 level', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
columns 1
|
||||
block
|
||||
columns 1
|
||||
block
|
||||
columns 3
|
||||
id1
|
||||
id2
|
||||
id2.1(("XYZ"))
|
||||
end
|
||||
id48
|
||||
end
|
||||
id3
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL5: should align block widths and handle colums statements in deeper sub-blocks then 1 level (alt)', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
columns 1
|
||||
block
|
||||
id1
|
||||
id2
|
||||
block
|
||||
columns 1
|
||||
id3("Wider then")
|
||||
id5(("id5"))
|
||||
end
|
||||
end
|
||||
id4
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL6: should handle block arrows and spece statements', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
columns 3
|
||||
space:3
|
||||
ida idb idc
|
||||
id1 id2
|
||||
blockArrowId<["Label"]>(right)
|
||||
blockArrowId2<["Label"]>(left)
|
||||
blockArrowId3<["Label"]>(up)
|
||||
blockArrowId4<["Label"]>(down)
|
||||
blockArrowId5<["Label"]>(x)
|
||||
blockArrowId6<["Label"]>(y)
|
||||
blockArrowId6<["Label"]>(x, down)
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL7: should handle different types of edges', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
columns 3
|
||||
A space:5
|
||||
A --o B
|
||||
A --> C
|
||||
A --x D
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL8: should handle sub-blocks without columns statements', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
columns 2
|
||||
C A B
|
||||
block
|
||||
D
|
||||
E
|
||||
end
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL9: should handle edges from blocks in sub blocks to other blocks', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
columns 3
|
||||
B space
|
||||
block
|
||||
D
|
||||
end
|
||||
D --> B
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL10: should handle edges from composite blocks', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
columns 3
|
||||
B space
|
||||
block BL
|
||||
D
|
||||
end
|
||||
BL --> B
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL11: should handle edges to composite blocks', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
columns 3
|
||||
B space
|
||||
block BL
|
||||
D
|
||||
end
|
||||
B --> BL
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL12: edges should handle labels', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
A
|
||||
space
|
||||
A -- "apa" --> E
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL13: should handle block arrows in different directions', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
columns 3
|
||||
space blockArrowId1<["down"]>(down) space
|
||||
blockArrowId2<["right"]>(right) blockArrowId3<["Sync"]>(x, y) blockArrowId4<["left"]>(left)
|
||||
space blockArrowId5<["up"]>(up) space
|
||||
blockArrowId6<["x"]>(x) space blockArrowId7<["y"]>(y)
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL14: should style statements and class statements', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
A
|
||||
B
|
||||
classDef blue fill:#66f,stroke:#333,stroke-width:2px;
|
||||
class A blue
|
||||
style B fill:#f9F,stroke:#333,stroke-width:4px
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL15: width alignment - D and E should share available space', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
block
|
||||
D
|
||||
E
|
||||
end
|
||||
db("This is the text in the box")
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL16: width alignment - C should be as wide as the composite block', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
block
|
||||
A("This is the text")
|
||||
B
|
||||
end
|
||||
C
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL16: width alignment - blocks shold be equal in width', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
A("This is the text")
|
||||
B
|
||||
C
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL17: block types 1 - square, rounded and circle', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
A["square"]
|
||||
B("rounded")
|
||||
C(("circle"))
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL18: block types 2 - odd, diamond and hexagon', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
A>"rect_left_inv_arrow"]
|
||||
B{"diamond"}
|
||||
C{{"hexagon"}}
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL19: block types 3 - stadium', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
A(["stadium"])
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL20: block types 4 - lean right, lean left, trapezoid and inv trapezoid', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
A[/"lean right"/]
|
||||
B[\"lean left"\]
|
||||
C[/"trapezoid"\]
|
||||
D[\"trapezoid alt"/]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL21: block types 1 - square, rounded and circle', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
A["square"]
|
||||
B("rounded")
|
||||
C(("circle"))
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL22: sizing - it should be possible to make a block wider', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
A("rounded"):2
|
||||
B:2
|
||||
C
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL23: sizing - it should be possible to make a composite block wider', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
block:2
|
||||
A
|
||||
end
|
||||
B
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL24: block in the middle with space on each side', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
columns 3
|
||||
space
|
||||
middle["In the middle"]
|
||||
space
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('BL25: space and an edge', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
columns 5
|
||||
A space B
|
||||
A --x B
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('BL26: block sizes for regular blocks', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
columns 3
|
||||
a["A wide one"] b:2 c:2 d
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('BL27: composite block with a set width - f should use the available space', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
columns 3
|
||||
a:3
|
||||
block:e:3
|
||||
f
|
||||
end
|
||||
g
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('BL23: composite block with a set width - f and g should split the available space', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
columns 3
|
||||
a:3
|
||||
block:e:3
|
||||
f
|
||||
g
|
||||
end
|
||||
h
|
||||
i
|
||||
j
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
});
|
36
cypress/integration/rendering/katex.spec.js
Normal file
36
cypress/integration/rendering/katex.spec.js
Normal file
@ -0,0 +1,36 @@
|
||||
import { imgSnapshotTest } from '../../helpers/util';
|
||||
|
||||
describe('Katex', () => {
|
||||
it('1: should render a complex Katex flowchart no htmlLabels', () => {
|
||||
imgSnapshotTest(
|
||||
`graph LR
|
||||
A["$$f(\\relax{x}) = \\int_{-\\infty}^\\infty \\hat{f}(\\xi)\\,e^{2 \\pi i \\xi x}\\,d\\xi$$"] -->|"$$\\Bigg(\\bigg(\\Big(\\big((\\frac{-b\\pm\\sqrt{b^2-4ac}}{2a})\\big)\\Big)\\bigg)\\Bigg)$$"| B("$$1+\\frac{e^{-2\\pi}} {1+\\frac{e^{-4\\pi}} {1+\\frac{e^{-6\\pi}} {1+\\frac{e^{-8\\pi}} {1+\\cdots}}}}$$")
|
||||
A -->|"$$\\overbrace{a+b+c}^{\\text{note}}$$"| C("$$\\phase{-78^\\circ}$$")
|
||||
B --> D("$$x = \\begin{cases} a &\\text{if } b \\\\ c &\\text{if } d \\end{cases}$$")
|
||||
C --> E("$$x(t)=c_1\\begin{bmatrix}-\\cos{t}+\\sin{t}\\\\ 2\\cos{t} \\end{bmatrix}e^{2t}$$")`,
|
||||
{ fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
it('2: should render a Katex flowchart containing the Greek alphabet', () => {
|
||||
imgSnapshotTest(
|
||||
`graph LR
|
||||
A["$$\\alpha\\beta\\gamma\\delta\\epsilon\\zeta\\eta\\theta\\iota\\kappa\\lambda\\mu\\nu\\xi\\omicron\\pi\\rho\\sigma\\tau\\upsilon\\phi\\chi\\psi\\omega$$"] --> B["$$\\Alpha\\Beta\\Gamma\\Delta\\Epsilon\\Zeta\\Eta\\Theta\\Iota\\Kappa\\Lambda\\Mu\\Nu\\Xi\\Omicron\\Pi\\Rho\\Sigma\\Tau\\Upsilon\\Phi\\Chi\\Psi\\Omega$$"]`,
|
||||
{ fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
it('3: should render a Katex flowchart containing set theory symbols', () => {
|
||||
imgSnapshotTest(
|
||||
`graph LR
|
||||
A["$$\\forall\\complement\\therefore\\emptyset\\exists\\subset\\because\\empty\\exist\\supset\\mapsto\\varnothing\\nexists\\mid\\to\\implies\\in\\land\\gets\\impliedby\\isin\\lor\\leftrightarrow\\iff\\notin\\ni\\notni\\lnot$$"] --> B["$$\\nabla\\Im\\Reals\\jmath\\partial\\image\\wp\\aleph\\Game\\weierp\\alef\\Finv\\N\\Z\\alefsym\\cnums\\natnums\\beth\\Complex\\R\\gimel\\ell\\Re\\daleth\\hbar\\real\\eth\\hslash\\reals$$"]`,
|
||||
{ fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
// TODO: changes made to develop between Feb 13 - Feb 23 cause this test to no longer function
|
||||
// it.skip('4: should render an error box originating from Katex', () => {
|
||||
// imgSnapshotTest(
|
||||
// `graph LR
|
||||
// A["$$\\shouldBeError$$"]`,
|
||||
// { fontFamily: 'courier' }
|
||||
// );
|
||||
// });
|
||||
});
|
@ -375,6 +375,26 @@ context('Sequence diagram', () => {
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('should have actor-top and actor-bottom classes on top and bottom actor box and symbol', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
actor Bob
|
||||
Alice->>Bob: Hi Bob
|
||||
Bob->>Alice: Hi Alice
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('.actor').should('have.class', 'actor-top');
|
||||
cy.get('.actor-man').should('have.class', 'actor-top');
|
||||
cy.get('.actor.actor-top').should('not.have.class', 'actor-bottom');
|
||||
cy.get('.actor-man.actor-top').should('not.have.class', 'actor-bottom');
|
||||
|
||||
cy.get('.actor').should('have.class', 'actor-bottom');
|
||||
cy.get('.actor-man').should('have.class', 'actor-bottom');
|
||||
cy.get('.actor.actor-bottom').should('not.have.class', 'actor-top');
|
||||
cy.get('.actor-man.actor-bottom').should('not.have.class', 'actor-top');
|
||||
});
|
||||
it('should render long notes left of actor', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
|
@ -17,24 +17,30 @@
|
||||
<style>
|
||||
body {
|
||||
/* background: rgb(221, 208, 208); */
|
||||
/* background:#333; */
|
||||
background: #333;
|
||||
font-family: 'Arial';
|
||||
/* font-size: 18px !important; */
|
||||
}
|
||||
h1 {
|
||||
color: grey;
|
||||
}
|
||||
.mermaid {
|
||||
border: 1px solid #ddd;
|
||||
margin: 10px;
|
||||
}
|
||||
.mermaid2 {
|
||||
display: none;
|
||||
}
|
||||
.mermaid svg {
|
||||
/* font-size: 18px !important; */
|
||||
background-color: #efefef;
|
||||
background-image: radial-gradient(#fff 51%, transparent 91%),
|
||||
radial-gradient(#fff 51%, transparent 91%);
|
||||
/* background-color: #efefef; */
|
||||
background-color: #333;
|
||||
background-image: radial-gradient(#333 51%, transparent 91%),
|
||||
radial-gradient(#333 51%, transparent 91%);
|
||||
background-size: 20px 20px;
|
||||
background-position: 0 0, 10px 10px;
|
||||
background-repeat: repeat;
|
||||
border: 2px solid rgb(131, 142, 205);
|
||||
}
|
||||
.malware {
|
||||
position: fixed;
|
||||
@ -58,46 +64,192 @@
|
||||
</head>
|
||||
<body>
|
||||
<pre id="diagram" class="mermaid">
|
||||
flowchart TB
|
||||
C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z & A1 & A2 & A3 & A4 & A5 & A6 & A7 & A8
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
|
||||
C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z & A1 & A2 & A3 & A4 & A5 & A6 & A7 & A8
|
||||
block-beta
|
||||
blockArrowId<["Label"]>(right)
|
||||
blockArrowId2<["Label"]>(left)
|
||||
blockArrowId3<["Label"]>(up)
|
||||
blockArrowId4<["Label"]>(down)
|
||||
blockArrowId5<["Label"]>(x)
|
||||
blockArrowId6<["Label"]>(y)
|
||||
blockArrowId6<["Label"]>(x, down)
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
block:e:4
|
||||
columns 2
|
||||
f
|
||||
g
|
||||
end
|
||||
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
block:e:4
|
||||
columns 2
|
||||
f
|
||||
g
|
||||
h
|
||||
end
|
||||
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
columns 4
|
||||
a b c d
|
||||
block:e:4
|
||||
columns 2
|
||||
f
|
||||
g
|
||||
h
|
||||
end
|
||||
i:4
|
||||
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
flowchart TB
|
||||
A & A & A & A & A & A & A & A ---> C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z
|
||||
flowchart LR
|
||||
X-- "y" -->z
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
flowchart TB
|
||||
A1 & A2 & A3 & A4 & A5 & A6 & A7 & A8 --> C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z
|
||||
block-beta
|
||||
columns 5
|
||||
A space B
|
||||
A --x B
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
block-beta
|
||||
columns 3
|
||||
a["A wide one"] b:2 c:2 d
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
block-beta
|
||||
block:e
|
||||
f
|
||||
end
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
block-beta
|
||||
columns 3
|
||||
a:3
|
||||
block:e:3
|
||||
f
|
||||
end
|
||||
g
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
block-beta
|
||||
columns 3
|
||||
a:3
|
||||
block:e:3
|
||||
f
|
||||
g
|
||||
end
|
||||
h
|
||||
i
|
||||
j
|
||||
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
block-beta
|
||||
columns 3
|
||||
a b:2
|
||||
block:e:3
|
||||
f
|
||||
end
|
||||
g h i
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
columns 3
|
||||
a b c
|
||||
e:3
|
||||
f g h
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
columns 1
|
||||
db(("DB"))
|
||||
blockArrowId6<[" "]>(down)
|
||||
block:ID
|
||||
A
|
||||
B["A wide one in the middle"]
|
||||
C
|
||||
end
|
||||
space
|
||||
D
|
||||
ID --> D
|
||||
C --> D
|
||||
style B fill:#f9F,stroke:#333,stroke-width:4px
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
columns 5
|
||||
A1:3
|
||||
A2:1
|
||||
A3
|
||||
B1 B2 B3:3
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
block-beta
|
||||
block
|
||||
D
|
||||
E
|
||||
end
|
||||
db("This is the text in the box")
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
block-beta
|
||||
|
||||
block
|
||||
D
|
||||
end
|
||||
A["A: I am a wide one"]
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
block-beta
|
||||
A["square"]
|
||||
B("rounded")
|
||||
C(("circle"))
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
block-beta
|
||||
A>"rect_left_inv_arrow"]
|
||||
B{"diamond"}
|
||||
C{{"hexagon"}}
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
block-beta
|
||||
A(["stadium"])
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
block-beta
|
||||
%% A[["subroutine"]]
|
||||
%% B[("cylinder")]
|
||||
C>"surprise"]
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
block-beta
|
||||
A[/"lean right"/]
|
||||
B[\"lean left"\]
|
||||
C[/"trapezoid"\]
|
||||
D[\"trapezoid"/]
|
||||
</pre>
|
||||
|
||||
<pre id="diagram" class="mermaid2">
|
||||
flowchart
|
||||
Node1:::class1 --> Node2:::class2
|
||||
Node1:::class1 --> Node3:::class2
|
||||
Node3 --> Node4((I am a circle)):::larger
|
||||
B
|
||||
style B fill:#f9F,stroke:#333,stroke-width:4px
|
||||
</pre>
|
||||
|
||||
classDef class1 fill:lightblue
|
||||
classDef class2 fill:pink
|
||||
classDef larger font-size:30px,fill:yellow
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
stateDiagram-v2
|
||||
[*] --> Still
|
||||
Still --> [*]
|
||||
Still --> Moving
|
||||
Moving --> Still
|
||||
Moving --> Crash
|
||||
Crash --> [*] </pre
|
||||
>
|
||||
flowchart LR
|
||||
a1 -- apa --> b1
|
||||
</pre>
|
||||
|
||||
<pre id="diagram" class="mermaid2">
|
||||
flowchart RL
|
||||
subgraph "`one`"
|
||||
a1 -- l1 --> a2
|
||||
a1 -- l2 --> a2
|
||||
end
|
||||
subgraph "`one`"
|
||||
id
|
||||
end
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
flowchart RL
|
||||
@ -442,14 +594,8 @@ mindmap
|
||||
// useMaxWidth: false,
|
||||
// });
|
||||
mermaid.initialize({
|
||||
flowchart: { titleTopMargin: 10 },
|
||||
fontFamily: 'courier',
|
||||
sequence: {
|
||||
actorFontFamily: 'courier',
|
||||
noteFontFamily: 'courier',
|
||||
messageFontFamily: 'courier',
|
||||
},
|
||||
fontSize: 16,
|
||||
theme: 'dark',
|
||||
startOnLoad: true,
|
||||
logLevel: 0,
|
||||
});
|
||||
function callback() {
|
||||
|
139
demos/block.html
Normal file
139
demos/block.html
Normal file
@ -0,0 +1,139 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/html">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Mermaid Block diagram demo page</title>
|
||||
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Block diagram demos</h1>
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
columns 1
|
||||
db(("DB"))
|
||||
blockArrowId6<[" "]>(down)
|
||||
block:ID
|
||||
A
|
||||
B["A wide one in the middle"]
|
||||
C
|
||||
end
|
||||
space
|
||||
D
|
||||
ID --> D
|
||||
C --> D
|
||||
style B fill:#f9F,stroke:#333,stroke-width:4px
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
A1["square"]
|
||||
B1("rounded")
|
||||
C1(("circle"))
|
||||
A2>"rect_left_inv_arrow"]
|
||||
B2{"diamond"}
|
||||
C2{{"hexagon"}}
|
||||
</pre>
|
||||
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
A1(["stadium"])
|
||||
A2[["subroutine"]]
|
||||
B1[("cylinder")]
|
||||
C1>"surprise"]
|
||||
A3[/"lean right"/]
|
||||
B2[\"lean left"\]
|
||||
C2[/"trapezoid"\]
|
||||
D2[\"trapezoid"/]
|
||||
</pre>
|
||||
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
block:e:4
|
||||
columns 2
|
||||
f
|
||||
g
|
||||
end
|
||||
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
block:e:4
|
||||
columns 2
|
||||
f
|
||||
g
|
||||
h
|
||||
end
|
||||
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
columns 3
|
||||
a:3
|
||||
block:e:3
|
||||
f
|
||||
g
|
||||
end
|
||||
h
|
||||
i
|
||||
j
|
||||
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
columns 4
|
||||
a b c d
|
||||
block:e:4
|
||||
columns 2
|
||||
f
|
||||
g
|
||||
h
|
||||
end
|
||||
i:4
|
||||
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
flowchart LR
|
||||
X-- "a label" -->z
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
columns 5
|
||||
A space B
|
||||
A --x B
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
columns 3
|
||||
a["A wide one"] b:2 c:2 d
|
||||
</pre>
|
||||
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
columns 3
|
||||
a b c
|
||||
e:3
|
||||
f g h
|
||||
</pre>
|
||||
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
|
||||
A1:3
|
||||
A2:1
|
||||
A3
|
||||
</pre>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
mermaid.initialize({
|
||||
theme: 'default',
|
||||
logLevel: 3,
|
||||
securityLevel: 'loose',
|
||||
block: {
|
||||
padding: 10,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1102,6 +1102,57 @@
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Sample 20</h2>
|
||||
<h3>graph</h3>
|
||||
<pre class="mermaid">
|
||||
graph LR
|
||||
A["$$f(\relax{x}) = \int_{-\infty}^\infty \hat{f}(\xi)\,e^{2 \pi i \xi x}\,d\xi$$"] -->|"$$\Bigg(\bigg(\Big(\big((\frac{-b\pm\sqrt{b^2-4ac}}{2a})\big)\Big)\bigg)\Bigg)$$"| B("$$1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {1+\frac{e^{-6\pi}} {1+\frac{e^{-8\pi}} {1+\cdots}}}}$$")
|
||||
A -->|"$$\overbrace{a+b+c}^{\text{note}}$$"| C("$$\phase{-78^\circ}$$")
|
||||
B --> D("$$x = \begin{cases} a &\text{if } b \\ c &\text{if } d \end{cases}$$")
|
||||
C --> E("$$x(t)=c_1\begin{bmatrix}-\cos{t}+\sin{t}\\ 2\cos{t} \end{bmatrix}e^{2t}$$")
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h3>flowchart</h3>
|
||||
<pre class="mermaid">
|
||||
flowchart LR
|
||||
A["$$f(\relax{x}) = \int_{-\infty}^\infty \hat{f}(\xi)\,e^{2 \pi i \xi x}\,d\xi$$"] -->|"$$\Bigg(\bigg(\Big(\big((\frac{-b\pm\sqrt{b^2-4ac}}{2a})\big)\Big)\bigg)\Bigg)$$"| B("$$1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {1+\frac{e^{-6\pi}} {1+\frac{e^{-8\pi}} {1+\cdots}}}}$$")
|
||||
A -->|"$$\overbrace{a+b+c}^{\text{note}}$$"| C("$$\phase{-78^\circ}$$")
|
||||
B --> D("$$x = \begin{cases} a &\text{if } b \\ c &\text{if } d \end{cases}$$")
|
||||
C --> E("$$x(t)=c_1\begin{bmatrix}-\cos{t}+\sin{t}\\ 2\cos{t} \end{bmatrix}e^{2t}$$")
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Sample 21</h2>
|
||||
<h3>graph</h3>
|
||||
<pre class="mermaid">
|
||||
graph LR
|
||||
A["$$\alpha\beta\gamma\delta\epsilon\zeta\eta\theta\iota\kappa\lambda\mu\nu\xi\omicron\pi\rho\sigma\tau\upsilon\phi\chi\psi\omega$$"] --> B["$$\Alpha\Beta\Gamma\Delta\Epsilon\Zeta\Eta\Theta\Iota\Kappa\Lambda\Mu\Nu\Xi\Omicron\Pi\Rho\Sigma\Tau\Upsilon\Phi\Chi\Psi\Omega$$"]
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h3>flowchart</h3>
|
||||
<pre class="mermaid">
|
||||
graph LR
|
||||
A["$$\alpha\beta\gamma\delta\epsilon\zeta\eta\theta\iota\kappa\lambda\mu\nu\xi\omicron\pi\rho\sigma\tau\upsilon\phi\chi\psi\omega$$"] --> B["$$\Alpha\Beta\Gamma\Delta\Epsilon\Zeta\Eta\Theta\Iota\Kappa\Lambda\Mu\Nu\Xi\Omicron\Pi\Rho\Sigma\Tau\Upsilon\Phi\Chi\Psi\Omega$$"]
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h2>Sample 22</h2>
|
||||
<h3>graph</h3>
|
||||
<pre class="mermaid">
|
||||
graph LR
|
||||
A["$$\forall\complement\therefore\emptyset\exists\subset\because\empty\exist\supset\mapsto\varnothing\nexists\mid\to\implies\in\land\gets\impliedby\isin\lor\leftrightarrow\iff\notin\ni\notni\lnot$$"] --> B["$$\nabla\Im\Reals\jmath\partial\image\wp\aleph\Game\weierp\alef\Finv\N\Z\alefsym\cnums\natnums\beth\Complex\R\gimel\ell\Re\daleth\hbar\real\eth\hslash\reals$$"]
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<h3>flowchart</h3>
|
||||
<pre class="mermaid">
|
||||
graph LR
|
||||
A["$$\forall\complement\therefore\emptyset\exists\subset\because\empty\exist\supset\mapsto\varnothing\nexists\mid\to\implies\in\land\gets\impliedby\isin\lor\leftrightarrow\iff\notin\ni\notni\lnot$$"] --> B["$$\nabla\Im\Reals\jmath\partial\image\wp\aleph\Game\weierp\alef\Finv\N\Z\alefsym\cnums\natnums\beth\Complex\R\gimel\ell\Re\daleth\hbar\real\eth\hslash\reals$$"]
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<hr />
|
||||
|
||||
<pre class="mermaid">
|
||||
@ -1524,11 +1575,11 @@
|
||||
F{Flow 2} == Choice 2.1 ==> H[Feedback node]
|
||||
H[Feedback node] ==> B[Step 1]
|
||||
F{Flow 2} == Choice 2.2 ==> G((Finish))
|
||||
|
||||
|
||||
linkStyle 0,1,4,6,7,8,9 stroke:gold, stroke-width:4px
|
||||
|
||||
classDef active_node fill:#0CF,stroke:#09F,stroke-width:6px
|
||||
classDef unactive_node fill:#e0e0e0,stroke:#bdbdbd,stroke-width:3px
|
||||
classDef unactive_node fill:#e0e0e0,stroke:#bdbdbd,stroke-width:3px
|
||||
classDef bugged_node fill:#F88,stroke:#F22,stroke-width:3px
|
||||
classDef start_node,finish_node fill:#3B1,stroke:#391,stroke-width:8px
|
||||
|
||||
|
@ -81,6 +81,9 @@
|
||||
<li>
|
||||
<h2><a href="./sankey.html">Sankey</a></h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2><a href="./block.html">Layered Blocks</a></h2>
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<body>
|
||||
<h1>Pie chart demos</h1>
|
||||
<pre class="mermaid">
|
||||
pie title Pets adopted by volunteers
|
||||
pie title Default text position: Animal adoption
|
||||
accTitle: simple pie char demo
|
||||
accDescr: pie chart with 3 sections: dogs, cats, rats. Most are dogs.
|
||||
"Dogs": 386
|
||||
@ -27,7 +27,7 @@
|
||||
<pre class="mermaid">
|
||||
%%{init: {"pie": {"textPosition": 0.9}, "themeVariables": {"pieOuterStrokeWidth": "5px"}}}%%
|
||||
pie
|
||||
title Key elements in Product X
|
||||
title Offset labels close to border: Product X
|
||||
accTitle: Key elements in Product X
|
||||
accDescr: This is a pie chart showing the key elements in Product X.
|
||||
"Calcium": 42.96
|
||||
@ -36,6 +36,19 @@
|
||||
"Iron": 5
|
||||
</pre>
|
||||
|
||||
<pre class="mermaid">
|
||||
%%{init: {"pie": {"textPosition": 0.45}, "themeVariables": {"pieOuterStrokeWidth": "5px"}}}%%
|
||||
pie
|
||||
title Centralized labels: Languages
|
||||
accTitle: Key elements in Product X
|
||||
accDescr: This is a pie chart showing the key elements in Product X.
|
||||
"JavaScript": 30
|
||||
"Python": 25
|
||||
"Java": 20
|
||||
"C#": 15
|
||||
"Others": 10
|
||||
</pre>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
mermaid.initialize({
|
||||
|
@ -16,9 +16,9 @@
|
||||
<body>
|
||||
<h1>Sequence diagram demos</h1>
|
||||
<pre class="mermaid">
|
||||
sequenceDiagram
|
||||
accTitle: test the accTitle
|
||||
accDescr: Test a description
|
||||
sequenceDiagram
|
||||
accTitle: test the accTitle
|
||||
accDescr: Test a description
|
||||
|
||||
participant Alice
|
||||
participant Bob
|
||||
@ -31,39 +31,39 @@
|
||||
rect rgb(200, 220, 100)
|
||||
rect rgb(200, 255, 200)
|
||||
|
||||
Alice ->> Bob: Hello Bob, how are you?
|
||||
Bob-->>John: How about you John?
|
||||
end
|
||||
Alice ->> Bob: Hello Bob, how are you?
|
||||
Bob-->>John: How about you John?
|
||||
end
|
||||
|
||||
Bob--x Alice: I am good thanks!
|
||||
Bob-x John: I am good thanks!
|
||||
Note right of John: John thinks a long<br />long time, so long<br />that the text does<br />not fit on a row.
|
||||
Bob--x Alice: I am good thanks!
|
||||
Bob-x John: I am good thanks!
|
||||
Note right of John: John thinks a long<br />long time, so long<br />that the text does<br />not fit on a row.
|
||||
|
||||
Bob-->Alice: Checking with John...
|
||||
Note over John:wrap: John looks like he's still thinking, so Bob prods him a bit.
|
||||
Bob-x John: Hey John - we're still waiting to know<br />how you're doing
|
||||
Note over John:nowrap: John's trying hard not to break his train of thought.
|
||||
Bob-x John:wrap: John! Are you still debating about how you're doing? How long does it take??
|
||||
Note over John: After a few more moments, John<br />finally snaps out of it.
|
||||
end
|
||||
Bob-->Alice: Checking with John...
|
||||
Note over John:wrap: John looks like he's still thinking, so Bob prods him a bit.
|
||||
Bob-x John: Hey John - we're still waiting to know<br />how you're doing
|
||||
Note over John:nowrap: John's trying hard not to break his train of thought.
|
||||
Bob-x John:wrap: John! Are you still debating about how you're doing? How long does it take??
|
||||
Note over John: After a few more moments, John<br />finally snaps out of it.
|
||||
end
|
||||
|
||||
autonumber off
|
||||
alt either this
|
||||
Alice->>+John: Yes
|
||||
John-->>-Alice: OK
|
||||
else or this
|
||||
autonumber
|
||||
Alice->>John: No
|
||||
else or this will happen
|
||||
Alice->John: Maybe
|
||||
end
|
||||
autonumber 200
|
||||
par this happens in parallel
|
||||
Alice -->> Bob: Parallel message 1
|
||||
and
|
||||
Alice -->> John: Parallel message 2
|
||||
end
|
||||
</pre>
|
||||
autonumber off
|
||||
alt either this
|
||||
Alice->>+John: Yes
|
||||
John-->>-Alice: OK
|
||||
else or this
|
||||
autonumber
|
||||
Alice->>John: No
|
||||
else or this will happen
|
||||
Alice->John: Maybe
|
||||
end
|
||||
autonumber 200
|
||||
par this happens in parallel
|
||||
Alice -->> Bob: Parallel message 1
|
||||
and
|
||||
Alice -->> John: Parallel message 2
|
||||
end
|
||||
</pre>
|
||||
<hr />
|
||||
<pre class="mermaid">
|
||||
---
|
||||
@ -153,18 +153,18 @@
|
||||
<hr />
|
||||
|
||||
<pre class="mermaid">
|
||||
sequenceDiagram
|
||||
box lightgreen Alice & John
|
||||
participant A
|
||||
participant J
|
||||
end
|
||||
box Another Group very very long description not wrapped
|
||||
participant B
|
||||
end
|
||||
A->>J: Hello John, how are you?
|
||||
J->>A: Great!
|
||||
A->>B: Hello Bob, how are you ?
|
||||
</pre
|
||||
sequenceDiagram
|
||||
box lightgreen Alice & John
|
||||
participant A
|
||||
participant J
|
||||
end
|
||||
box Another Group very very long description not wrapped
|
||||
participant B
|
||||
end
|
||||
A->>J: Hello John, how are you?
|
||||
J->>A: Great!
|
||||
A->>B: Hello Bob, how are you ?
|
||||
</pre
|
||||
>
|
||||
<hr />
|
||||
|
||||
@ -187,7 +187,57 @@
|
||||
Note left of Bob: Alice/Bob Note
|
||||
end
|
||||
</pre>
|
||||
<pre class="mermaid">
|
||||
sequenceDiagram
|
||||
actor Alice
|
||||
actor John
|
||||
Alice-xJohn: Hello John, how are you?
|
||||
John--xAlice: Great!
|
||||
</pre>
|
||||
|
||||
<hr />
|
||||
|
||||
<pre class="mermaid">
|
||||
sequenceDiagram
|
||||
participant 1 as $$\frac{\lim_{x\rightarrow0}{\frac{1}{x}}}{\frac{-b\pm\sqrt{b^2-4ac}}{2a}}$$
|
||||
participant 2 as $$\beta$$
|
||||
participant 3 as $$\delta$$
|
||||
participant 4 as $$\frac{\frac{\lim_{x\rightarrow0}{\frac{1}{x}}}{\frac{-b\pm\sqrt{b^2-4ac}}{2a}}}{\frac{\text{d}}{\text{d}x}{x^2}}$$
|
||||
1->>2: $$\sqrt{2}$$
|
||||
note right of 2: $$\frac{1+\frac{1+\frac{1+\frac{1}{2}}{2}}{2}}{2}+\frac{-b\pm\sqrt{b^2-4ac}}{2a}$$
|
||||
2->>3: $$\frac{\lim_{x\rightarrow0}{\frac{1}{x}}}{\frac{-b\pm\sqrt{b^2-4ac}}{2a}}$$
|
||||
note right of 3: $$\frac{-b\pm\sqrt{b^2-4ac}}{2a}$$
|
||||
3->>4: $$\lim_{x\rightarrow0}{\frac{1}{x}}$$;
|
||||
note right of 4: multiline
|
||||
4->>1: multiline<br />using #lt;br /#gt;
|
||||
note right of 1: multiline<br />$$\frac{1}{2}$$<br />3rd line
|
||||
</pre>
|
||||
<hr />
|
||||
<pre class="mermaid">
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
participant 1 as $$\alpha$$lex
|
||||
participant 2 as $$\beta$$ob
|
||||
participant 3 as $$\theta$$iffany
|
||||
1->>2: Hello John, does $$\frac{1}{2}+1=2$$?
|
||||
loop $$\frac{1}{2}+1=2$$
|
||||
2->>2: $$\frac{1}{2}+1=\frac{3}{2}$$
|
||||
end
|
||||
Note right of 2: $$x = \begin{cases} 1 &\text{if } \frac{1}{2}+1=2 \\ 0 &\text{if } \frac{1}{2}+1\ne2 \end{cases}$$
|
||||
2-->>1: $$\frac{1}{2}+1\ne2\implies 1$$
|
||||
2->>3: $$\frac{\text{d}}{\text{d}x}{3x^2+2x+1}$$
|
||||
3-->>2: $$6x+2$$
|
||||
</pre>
|
||||
|
||||
<hr />
|
||||
|
||||
<pre class="mermaid">
|
||||
sequenceDiagram
|
||||
actor Alice
|
||||
actor John
|
||||
Alice-xJohn: Hello John, how are you?
|
||||
John--xAlice: Great!
|
||||
</pre>
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
mermaid.initialize({
|
||||
|
@ -137,7 +137,7 @@ config:
|
||||
plotReservedSpacePercent: 60
|
||||
---
|
||||
xychart-beta
|
||||
title "Sales Revene"
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
|
||||
@ -163,7 +163,7 @@ config:
|
||||
plotColorPalette: "#008000, #faba63"
|
||||
---
|
||||
xychart-beta
|
||||
title "Sales Revene"
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
|
||||
|
@ -8,7 +8,7 @@ services:
|
||||
tty: true
|
||||
working_dir: /mermaid
|
||||
mem_limit: '8G'
|
||||
entrypoint: '/mermaid/docker-entrypoint.sh'
|
||||
entrypoint: docker-entrypoint.sh
|
||||
environment:
|
||||
- NODE_OPTIONS=--max_old_space_size=8192
|
||||
volumes:
|
||||
|
@ -132,7 +132,7 @@ All tests should run successfully without any errors or failures.
|
||||
|
||||
## Workflow
|
||||
|
||||
Contributing process is very simple and strightforward:
|
||||
Contributing process is very simple and straightforward:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
@ -370,13 +370,13 @@ If the users have no way to know that things have changed, then you haven't real
|
||||
Likewise, if users don't know that there is a new feature that you've implemented, it will forever remain unknown and unused.
|
||||
|
||||
The documentation has to be updated for users to know that things have been changed and added!
|
||||
If you are adding a new feature, add `(v<MERMAID_RELEASE_VERSION>+)` in the title or description. It will be replaced automatically with the current version number when the release happens.
|
||||
If you are adding a new feature, add `(v10.8.0+)` in the title or description. It will be replaced automatically with the current version number when the release happens.
|
||||
|
||||
eg: `# Feature Name (v<MERMAID_RELEASE_VERSION>+)`
|
||||
eg: `# Feature Name (v10.8.0+)`
|
||||
|
||||
We know it can sometimes be hard to code _and_ write user documentation.
|
||||
|
||||
Create another issue specifically for the documentation.\
|
||||
Create another issue specifically for the documentation.
|
||||
You will need to help with the PR, but definitely ask for help if you feel stuck.
|
||||
When it feels hard to write stuff out, explaining it to someone and having that person ask you clarifying questions can often be 80% of the work!
|
||||
|
||||
@ -401,14 +401,14 @@ The contents of [mermaid.js.org](https://mermaid.js.org/) are based on the docs
|
||||
flowchart LR
|
||||
classDef default fill:#fff,color:black,stroke:black
|
||||
|
||||
source["Edit /packages/mermaid/src/docs"] -- automatic processing--> published["View /docs which will be publised on Official Website"]
|
||||
source["Edit /packages/mermaid/src/docs"] -- automatic processing--> published["View /docs which will be published on Official Website"]
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
classDef default fill:#fff,color:black,stroke:black
|
||||
|
||||
source["Edit /packages/mermaid/src/docs"] -- automatic processing--> published["View /docs which will be publised on Official Website"]
|
||||
source["Edit /packages/mermaid/src/docs"] -- automatic processing--> published["View /docs which will be published on Official Website"]
|
||||
```
|
||||
|
||||
### Running the Documentation Website Locally
|
||||
@ -519,3 +519,5 @@ You have successfully submitted your improvements! What is next?
|
||||
- When a release is ready, the `release/x.x.x` branch will be created, extensively tested and knsv will be in charge of the release process.
|
||||
|
||||
Thanks for you help!
|
||||
|
||||
<!--- cspell:ignore florbs --->
|
||||
|
@ -43,7 +43,7 @@ Where to start:
|
||||
- You could work on a new feature! [These](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue+is%3Aopen+label%3A%22Area%3A+Development%22+label%3A%22Type%3A+Enhancement%22+label%3A%22Status%3A+Approved%22+) are some ideas!
|
||||
- You could confirm the bugs in [these issues](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue+is%3Aopen+label%3A%22Status%3A+Triage%22++label%3A%22Type%3A+Bug+%2F+Error%22).
|
||||
|
||||
[Join our slack community if you want closer contact!](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)
|
||||
[You can join our Discord server if you want closer contact!](https://discord.gg/AgrbSrBer3)
|
||||
|
||||
## A Question Or a Suggestion?
|
||||
|
||||
@ -55,6 +55,6 @@ If you have faced a vulnerability [report it to us](./security.md).
|
||||
|
||||
Don't get daunted if it is hard in the beginning. We have a great community with only encouraging words. So, if you get stuck, ask for help and hints in the Slack forum. If you want to show off something good, show it off there.
|
||||
|
||||
[Join our Slack community if you want closer contact!](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)
|
||||
[You can join our Discord server if you want closer contact!](https://discord.gg/AgrbSrBer3)
|
||||
|
||||
![Image of superhero wishing you good luck](https://media.giphy.com/media/l49JHz7kJvl6MCj3G/giphy.gif)
|
||||
|
@ -19,7 +19,7 @@ Mermaid will automatically insert the [aria-roledescription](#aria-roledescripti
|
||||
|
||||
The [aria-roledescription](https://www.w3.org/TR/wai-aria-1.1/#aria-roledescription) for the SVG HTML element is set to the diagram type key. (Note this may be slightly different than the keyword used for the diagram in the diagram text.)
|
||||
|
||||
For example: The diagram type key for a state diagram is "stateDiagram". Here (a part of) the HTML of the SVG tag that shows the automatically inserted aria-roledscription set to "stateDiagram". _(Note that some of the SVG attributes and the SVG contents are omitted for clarity.):_
|
||||
For example: The diagram type key for a state diagram is "stateDiagram". Here (a part of) the HTML of the SVG tag that shows the automatically inserted aria-roledescription set to "stateDiagram". _(Note that some of the SVG attributes and the SVG contents are omitted for clarity.):_
|
||||
|
||||
```html
|
||||
<svg
|
||||
|
86
docs/config/math.md
Normal file
86
docs/config/math.md
Normal file
@ -0,0 +1,86 @@
|
||||
> **Warning**
|
||||
>
|
||||
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
|
||||
>
|
||||
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/config/math.md](../../packages/mermaid/src/docs/config/math.md).
|
||||
|
||||
# Math Configuration (v\<MERMAID_RELEASE_VERSION>+)
|
||||
|
||||
Mermaid supports rendering mathematical expressions through the [KaTeX](https://katex.org/) typesetter.
|
||||
|
||||
## Usage
|
||||
|
||||
To render math within a diagram, surround the mathematical expression with the `$$` delimiter.
|
||||
|
||||
Note that at the moment, the only supported diagrams are below:
|
||||
|
||||
### Flowcharts
|
||||
|
||||
```mermaid-example
|
||||
graph LR
|
||||
A["$$x^2$$"] -->|"$$\sqrt{x+3}$$"| B("$$\frac{1}{2}$$")
|
||||
A -->|"$$\overbrace{a+b+c}^{\text{note}}$$"| C("$$\pi r^2$$")
|
||||
B --> D("$$x = \begin{cases} a &\text{if } b \\ c &\text{if } d \end{cases}$$")
|
||||
C --> E("$$x(t)=c_1\begin{bmatrix}-\cos{t}+\sin{t}\\ 2\cos{t} \end{bmatrix}e^{2t}$$")
|
||||
```
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A["$$x^2$$"] -->|"$$\sqrt{x+3}$$"| B("$$\frac{1}{2}$$")
|
||||
A -->|"$$\overbrace{a+b+c}^{\text{note}}$$"| C("$$\pi r^2$$")
|
||||
B --> D("$$x = \begin{cases} a &\text{if } b \\ c &\text{if } d \end{cases}$$")
|
||||
C --> E("$$x(t)=c_1\begin{bmatrix}-\cos{t}+\sin{t}\\ 2\cos{t} \end{bmatrix}e^{2t}$$")
|
||||
```
|
||||
|
||||
### Sequence
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
participant 1 as $$\alpha$$
|
||||
participant 2 as $$\beta$$
|
||||
1->>2: Solve: $$\sqrt{2+2}$$
|
||||
2-->>1: Answer: $$2$$
|
||||
Note right of 2: $$\sqrt{2+2}=\sqrt{4}=2$$
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
participant 1 as $$\alpha$$
|
||||
participant 2 as $$\beta$$
|
||||
1->>2: Solve: $$\sqrt{2+2}$$
|
||||
2-->>1: Answer: $$2$$
|
||||
Note right of 2: $$\sqrt{2+2}=\sqrt{4}=2$$
|
||||
```
|
||||
|
||||
## Legacy Support
|
||||
|
||||
By default, MathML is used for rendering mathematical expressions. If you have users on [unsupported browsers](https://caniuse.com/?search=mathml), `legacyMathML` can be set in the config to fall back to CSS rendering. Note that **you must provide KaTeX's stylesheets on your own** as they do not come bundled with Mermaid.
|
||||
|
||||
Example with legacy mode enabled (the latest version of KaTeX's stylesheet can be found on their [docs](https://katex.org/docs/browser.html)):
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<!-- KaTeX requires the use of the HTML5 doctype. Without it, KaTeX may not render properly -->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Please ensure the stylesheet's version matches with the KaTeX version in your package-lock -->
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/katex@{version_number}/dist/katex.min.css"
|
||||
integrity="sha384-{hash}"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
mermaid.initialize({
|
||||
legacyMathML: true,
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
@ -96,7 +96,7 @@ mermaid.initialize(config);
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:608](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L608)
|
||||
[mermaidAPI.ts:607](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L607)
|
||||
|
||||
## Functions
|
||||
|
||||
|
@ -65,7 +65,7 @@ Example of `init` directive setting the `theme` to `forest`:
|
||||
a --> b
|
||||
```
|
||||
|
||||
> **Reminder**: the only theme that can be customed is the `base` theme. The following section covers how to use `themeVariables` for customizations.
|
||||
> **Reminder**: the only theme that can be customized is the `base` theme. The following section covers how to use `themeVariables` for customizations.
|
||||
|
||||
## Customizing Themes with `themeVariables`
|
||||
|
||||
|
@ -436,3 +436,8 @@ mermaid_config.startOnLoad = true;
|
||||
|
||||
> **Warning**
|
||||
> This way of setting the configuration is deprecated. Instead the preferred way is to use the initialize method. This functionality is only kept for backwards compatibility.
|
||||
|
||||
<!---
|
||||
cspell:locale en,en-gb
|
||||
cspell:ignore pumbaa
|
||||
--->
|
||||
|
@ -95,6 +95,8 @@ Blogging frameworks and platforms
|
||||
|
||||
Content Management Systems/Enterprise Content Management
|
||||
|
||||
- [ApostropheCMS](https://apostrophecms.com/)
|
||||
- [Extension for Mermaid.js](https://github.com/BoDonkey/mermaid-extension)
|
||||
- [Grav CMS](https://getgrav.org/)
|
||||
- [Mermaid Diagrams Plugin](https://github.com/DanielFlaum/grav-plugin-mermaid-diagrams)
|
||||
- [GitLab Markdown Adapter](https://github.com/Goutte/grav-plugin-gitlab-markdown-adapter)
|
||||
@ -215,23 +217,24 @@ Communication tools and platforms
|
||||
|
||||
### Browser Extensions
|
||||
|
||||
| Name | Chrome Web Store | Firefox Add-ons | Opera | Edge | Source/Repository |
|
||||
| ------------------------ | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
|
||||
| GitHub + Mermaid | - | [🦊🔗](https://addons.mozilla.org/firefox/addon/github-mermaid/) | - | - | [🐙🔗](https://github.com/BackMarket/github-mermaid-extension) |
|
||||
| Asciidoctor Live Preview | [🎡🔗](https://chrome.google.com/webstore/detail/asciidoctorjs-live-previe/iaalpfgpbocpdfblpnhhgllgbdbchmia) | - | - | [🌀🔗](https://microsoftedge.microsoft.com/addons/detail/asciidoctorjs-live-previ/pefkelkanablhjdekgdahplkccnbdggd?hl=en-US) | - |
|
||||
| Diagram Tab | - | - | - | - | [🐙🔗](https://github.com/khafast/diagramtab) |
|
||||
| Markdown Diagrams | [🎡🔗](https://chrome.google.com/webstore/detail/markdown-diagrams/pmoglnmodacnbbofbgcagndelmgaclel/) | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-diagrams/) | [🔴🔗](https://addons.opera.com/en/extensions/details/markdown-diagrams/) | [🌀🔗](https://microsoftedge.microsoft.com/addons/detail/markdown-diagrams/hceenoomhhdkjjijnmlclkpenkapfihe) | [🐙🔗](https://github.com/marcozaccari/markdown-diagrams-browser-extension/tree/master/doc/examples) |
|
||||
| Markdown Viewer | - | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-viewer-chrome/) | - | - | [🐙🔗](https://github.com/simov/markdown-viewer) |
|
||||
| Extensions for Mermaid | - | - | [🔴🔗](https://addons.opera.com/en/extensions/details/extensions-for-mermaid/) | - | [🐙🔗](https://github.com/Stefan-S/mermaid-extension) |
|
||||
| Chrome Diagrammer | [🎡🔗](https://chrome.google.com/webstore/detail/chrome-diagrammer/bkpbgjmkomfoakfklcjeoegkklgjnnpk) | - | - | - | - |
|
||||
| Mermaid Diagrams | [🎡🔗](https://chrome.google.com/webstore/detail/mermaid-diagrams/phfcghedmopjadpojhmmaffjmfiakfil) | - | - | - | - |
|
||||
| Monkeys | [🎡🔗](https://chrome.google.com/webstore/detail/monkeys-mermaid-for-githu/cplfdpoajbclbgphaphphcldamfkjlgi) | - | - | - | - |
|
||||
| Mermaid Previewer | [🎡🔗](https://chrome.google.com/webstore/detail/mermaid-previewer/oidjnlhbegipkcklbdfnbkikplpghfdl) | - | - | - | - |
|
||||
| Name | Chrome Web Store | Firefox Add-ons | Opera | Edge | Source/Repository |
|
||||
| ------------------------ | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
|
||||
| GitHub + Mermaid | - | [🦊🔗](https://addons.mozilla.org/firefox/addon/github-mermaid/) | - | - | [🐙🔗](https://github.com/BackMarket/github-mermaid-extension) |
|
||||
| Asciidoctor Live Preview | [🎡🔗](https://chromewebstore.google.com/detail/asciidoctorjs-live-previe/iaalpfgpbocpdfblpnhhgllgbdbchmia) | - | - | [🌀🔗](https://microsoftedge.microsoft.com/addons/detail/asciidoctorjs-live-previ/pefkelkanablhjdekgdahplkccnbdggd?hl=en-US) | - |
|
||||
| Diagram Tab | - | - | - | - | [🐙🔗](https://github.com/khafast/diagramtab) |
|
||||
| Markdown Diagrams | [🎡🔗](https://chromewebstore.google.com/detail/markdown-diagrams/pmoglnmodacnbbofbgcagndelmgaclel/) | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-diagrams/) | [🔴🔗](https://addons.opera.com/en/extensions/details/markdown-diagrams/) | [🌀🔗](https://microsoftedge.microsoft.com/addons/detail/markdown-diagrams/hceenoomhhdkjjijnmlclkpenkapfihe) | [🐙🔗](https://github.com/marcozaccari/markdown-diagrams-browser-extension/tree/master/doc/examples) |
|
||||
| Markdown Viewer | - | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-viewer-chrome/) | - | - | [🐙🔗](https://github.com/simov/markdown-viewer) |
|
||||
| Extensions for Mermaid | - | - | [🔴🔗](https://addons.opera.com/en/extensions/details/extensions-for-mermaid/) | - | [🐙🔗](https://github.com/Stefan-S/mermaid-extension) |
|
||||
| Chrome Diagrammer | [🎡🔗](https://chromewebstore.google.com/detail/chrome-diagrammer/bkpbgjmkomfoakfklcjeoegkklgjnnpk) | - | - | - | - |
|
||||
| Mermaid Diagrams | [🎡🔗](https://chromewebstore.google.com/detail/mermaid-diagrams/phfcghedmopjadpojhmmaffjmfiakfil) | - | - | - | - |
|
||||
| Monkeys | [🎡🔗](https://chromewebstore.google.com/detail/monkeys-mermaid-for-githu/cplfdpoajbclbgphaphphcldamfkjlgi) | - | - | - | - |
|
||||
| Mermaid Previewer | [🎡🔗](https://chromewebstore.google.com/detail/mermaid-previewer/oidjnlhbegipkcklbdfnbkikplpghfdl) | - | - | - | - |
|
||||
|
||||
### Other
|
||||
|
||||
- [Bisheng](https://www.npmjs.com/package/bisheng)
|
||||
- [bisheng-plugin-mermaid](https://github.com/yct21/bisheng-plugin-mermaid)
|
||||
- [Blazorade Mermaid: Render Mermaid diagrams in Blazor applications](https://github.com/Blazorade/Blazorade-Mermaid/wiki)
|
||||
- [Codemia: A tool to practice system design problems](https://codemia.io) ✅
|
||||
- [ExDoc](https://github.com/elixir-lang/ex_doc)
|
||||
- [Rendering Mermaid graphs](https://github.com/elixir-lang/ex_doc#rendering-mermaid-graphs)
|
||||
@ -248,5 +251,5 @@ Communication tools and platforms
|
||||
- [reveal-ck-mermaid-plugin](https://github.com/tmtm/reveal-ck-mermaid-plugin)
|
||||
- [mermaid-isomorphic](https://github.com/remcohaszing/mermaid-isomorphic)
|
||||
- [mermaid-server: Generate diagrams using a HTTP request](https://github.com/TomWright/mermaid-server)
|
||||
- [ExDoc](https://github.com/elixir-lang/ex_doc)
|
||||
- [Rendering Mermaid graphs](https://github.com/elixir-lang/ex_doc#rendering-mermaid-graphs)
|
||||
|
||||
<!--- cspell:ignore Blazorade --->
|
||||
|
@ -24,7 +24,7 @@ Currently pending [IANA](https://www.iana.org/) recognition.
|
||||
|
||||
### Mermaid Discord workspace
|
||||
|
||||
We would love to see what you create with Mermaid. Please share your creations with us in our [Discord](https://discord.gg/wwtabKgp8y) server [#showcase](https://discord.com/channels/1079455296289788015/1079502635054399649) channel.
|
||||
We would love to see what you create with Mermaid. Please share your creations with us in our [Discord](https://discord.gg/AgrbSrBer3) server [#showcase](https://discord.com/channels/1079455296289788015/1079502635054399649) channel.
|
||||
|
||||
### Add to Mermaid Ecosystem
|
||||
|
||||
|
@ -80,3 +80,5 @@ graph LR;
|
||||
**Output**
|
||||
|
||||
![Example graph of the Python integration](img/python-mermaid-integration.png)
|
||||
|
||||
<!--- cspell:ignore Elle Jaoude Neurodiverse graphbytes --->
|
||||
|
@ -22,7 +22,7 @@ It is a JavaScript based diagramming and charting tool that renders Markdown-ins
|
||||
[![Coverage Status](https://coveralls.io/repos/github/mermaid-js/mermaid/badge.svg?branch=master)](https://coveralls.io/github/mermaid-js/mermaid?branch=master)
|
||||
[![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid)
|
||||
[![NPM](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid)
|
||||
[![Join our Discord!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=discord&label=discord)](https://discord.gg/wwtabKgp8y)
|
||||
[![Join our Discord!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=discord&label=discord)](https://discord.gg/AgrbSrBer3)
|
||||
[![Twitter Follow](https://img.shields.io/twitter/follow/mermaidjs_?style=social)](https://twitter.com/mermaidjs_)
|
||||
|
||||
</div>
|
||||
@ -88,7 +88,7 @@ sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice->>John: Hello John, how are you?
|
||||
loop Healthcheck
|
||||
loop HealthCheck
|
||||
John->>John: Fight against hypochondria
|
||||
end
|
||||
Note right of John: Rational thoughts <br/>prevail!
|
||||
@ -102,7 +102,7 @@ sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice->>John: Hello John, how are you?
|
||||
loop Healthcheck
|
||||
loop HealthCheck
|
||||
John->>John: Fight against hypochondria
|
||||
end
|
||||
Note right of John: Rational thoughts <br/>prevail!
|
||||
|
@ -14,19 +14,6 @@ Create flowchart nodes, connect them with edges, update shapes, change colors, a
|
||||
|
||||
Read more about it in our latest [BLOG POST](https://www.mermaidchart.com/blog/posts/mermaid-chart-releases-new-visual-editor-for-flowcharts) and watch a [DEMO VIDEO](https://www.youtube.com/watch?v=5aja0gijoO0) on our YouTube page.
|
||||
|
||||
## 🎉 Mermaid Chart is running a Holiday promotion
|
||||
|
||||
### Use <span class="text-[#FE3470]">HOLIDAYS2023</span> to get a 14-day free trial and 25% off a Pro subscription
|
||||
|
||||
With a Pro subscription, you get access to:
|
||||
|
||||
- AI functionality
|
||||
- Team collaboration and multi-user editing
|
||||
- Unlimited diagrams and presentations
|
||||
- And more!
|
||||
|
||||
Redeem the promo code on the [Mermaid Chart website](https://www.mermaidchart.com/app/user/billing/checkout?coupon=HOLIDAYS2023).
|
||||
|
||||
## 📖 Blog posts
|
||||
|
||||
Visit our [Blog](./blog.md) to see the latest blog posts.
|
||||
|
@ -6,6 +6,12 @@
|
||||
|
||||
# Blog
|
||||
|
||||
## [How one data scientist uses Mermaid Chart to quickly and easily build flowcharts](https://www.mermaidchart.com/blog/posts/customer-spotlight-ari-tal/)
|
||||
|
||||
23 January 2024 · 4 mins
|
||||
|
||||
Read about how Ari Tal, a data scientist and founder of Leveling Up with XAI, utilizes Mermaid Chart for its easy-to-use flowchart creation capabilities to enhance his work in explainable AI (XAI).
|
||||
|
||||
## [Introducing Mermaid Chart’s JetBrains IDE Extension](https://www.mermaidchart.com/blog/posts/introducing-mermaid-charts-jetbrains-ide-extension/)
|
||||
|
||||
20 December 2023 · 5 mins
|
||||
|
706
docs/syntax/block.md
Normal file
706
docs/syntax/block.md
Normal file
@ -0,0 +1,706 @@
|
||||
> **Warning**
|
||||
>
|
||||
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
|
||||
>
|
||||
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/syntax/block.md](../../packages/mermaid/src/docs/syntax/block.md).
|
||||
|
||||
# Block Diagrams Documentation
|
||||
|
||||
## Introduction to Block Diagrams
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
columns 1
|
||||
db(("DB"))
|
||||
blockArrowId6<[" "]>(down)
|
||||
block:ID
|
||||
A
|
||||
B["A wide one in the middle"]
|
||||
C
|
||||
end
|
||||
space
|
||||
D
|
||||
ID --> D
|
||||
C --> D
|
||||
style B fill:#969,stroke:#333,stroke-width:4px
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 1
|
||||
db(("DB"))
|
||||
blockArrowId6<[" "]>(down)
|
||||
block:ID
|
||||
A
|
||||
B["A wide one in the middle"]
|
||||
C
|
||||
end
|
||||
space
|
||||
D
|
||||
ID --> D
|
||||
C --> D
|
||||
style B fill:#969,stroke:#333,stroke-width:4px
|
||||
```
|
||||
|
||||
### Definition and Purpose
|
||||
|
||||
Block diagrams are an intuitive and efficient way to represent complex systems, processes, or architectures visually. They are composed of blocks and connectors, where blocks represent the fundamental components or functions, and connectors show the relationship or flow between these components. This method of diagramming is essential in various fields such as engineering, software development, and process management.
|
||||
|
||||
The primary purpose of block diagrams is to provide a high-level view of a system, allowing for easy understanding and analysis without delving into the intricate details of each component. This makes them particularly useful for simplifying complex systems and for explaining the overall structure and interaction of components within a system.
|
||||
|
||||
Many people use mermaid flowcharts for this purpose. A side-effect of this is that the automatic layout sometimes move shapes to positions that the diagram maker does not want. Block diagrams use a different approach. In this diagram we give the author full control over where the shapes are positioned.
|
||||
|
||||
### General Use Cases
|
||||
|
||||
Block diagrams have a wide range of applications across various industries and disciplines. Some of the key use cases include:
|
||||
|
||||
- **Software Architecture**: In software development, block diagrams can be used to illustrate the architecture of a software application. This includes showing how different modules or services interact, data flow, and high-level component interaction.
|
||||
|
||||
- **Network Diagrams**: Block diagrams are ideal for representing network architectures in IT and telecommunications. They can depict how different network devices and services are interconnected, including routers, switches, firewalls, and the flow of data across the network.
|
||||
|
||||
- **Process Flowcharts**: In business and manufacturing, block diagrams can be employed to create process flowcharts. These flowcharts represent various stages of a business or manufacturing process, helping to visualize the sequence of steps, decision points, and the flow of control.
|
||||
|
||||
- **Electrical Systems**: Engineers use block diagrams to represent electrical systems and circuitry. They can illustrate the high-level structure of an electrical system, the interaction between different electrical components, and the flow of electrical currents.
|
||||
|
||||
- **Educational Purposes**: Block diagrams are also extensively used in educational materials to explain complex concepts and systems in a simplified manner. They help in breaking down and visualizing scientific theories, engineering principles, and technological systems.
|
||||
|
||||
These examples demonstrate the versatility of block diagrams in providing clear and concise representations of complex systems. Their simplicity and clarity make them a valuable tool for professionals across various fields to communicate complex ideas effectively.
|
||||
|
||||
In the following sections, we will delve into the specifics of creating and manipulating block diagrams using Mermaid, covering everything from basic syntax to advanced configurations and styling.
|
||||
|
||||
Creating block diagrams with Mermaid is straightforward and accessible. This section introduces the basic syntax and structure needed to start building simple diagrams. Understanding these foundational concepts is key to efficiently utilizing Mermaid for more complex diagramming tasks.
|
||||
|
||||
### Simple Block Diagrams
|
||||
|
||||
#### Basic Structure
|
||||
|
||||
At its core, a block diagram consists of blocks representing different entities or components. In Mermaid, these blocks are easily created using simple text labels. The most basic form of a block diagram can be a series of blocks without any connectors.
|
||||
|
||||
**Example - Simple Block Diagram**:
|
||||
To create a simple block diagram with three blocks labeled 'a', 'b', and 'c', the syntax is as follows:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
a b c
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
a b c
|
||||
```
|
||||
|
||||
This example will produce a horizontal sequence of three blocks. Each block is automatically spaced and aligned for optimal readability.
|
||||
|
||||
### Defining the number of columns to use
|
||||
|
||||
#### Column Usage
|
||||
|
||||
While simple block diagrams are linear and straightforward, more complex systems may require a structured layout. Mermaid allows for the organization of blocks into multiple columns, facilitating the creation of more intricate and detailed diagrams.
|
||||
|
||||
**Example - Multi-Column Diagram:**
|
||||
In scenarios where you need to distribute blocks across multiple columns, you can specify the number of columns and arrange the blocks accordingly. Here's how to create a block diagram with three columns and four blocks, where the fourth block appears in a second row:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
columns 3
|
||||
a b c d
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 3
|
||||
a b c d
|
||||
```
|
||||
|
||||
This syntax instructs Mermaid to arrange the blocks 'a', 'b', 'c', and 'd' across three columns, wrapping to the next row as needed. This feature is particularly useful for representing layered or multi-tiered systems, such as network layers or hierarchical structures.
|
||||
|
||||
These basic building blocks of Mermaid's block diagrams provide a foundation for more complex diagramming. The simplicity of the syntax allows for quick creation and iteration of diagrams, making it an efficient tool for visualizing ideas and concepts. In the next section, we'll explore advanced block configuration options, including setting block widths and creating composite blocks.
|
||||
|
||||
## 3. Advanced Block Configuration
|
||||
|
||||
Building upon the basics, this section delves into more advanced features of block diagramming in Mermaid. These features allow for greater flexibility and complexity in diagram design, accommodating a wider range of use cases and scenarios.
|
||||
|
||||
### Setting Block Width
|
||||
|
||||
#### Spanning Multiple Columns
|
||||
|
||||
In more complex diagrams, you may need blocks that span multiple columns to emphasize certain components or to represent larger entities. Mermaid allows for the adjustment of block widths to cover multiple columns, enhancing the diagram's readability and structure.
|
||||
|
||||
**Example - Block Spanning Multiple Columns**:
|
||||
To create a block diagram where one block spans across two columns, you can specify the desired width for each block:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
columns 3
|
||||
a["A label"] b:2 c:2 d
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 3
|
||||
a["A label"] b:2 c:2 d
|
||||
```
|
||||
|
||||
In this example, the block labeled "A wide one" spans two columns, while blocks 'b', 'c', and 'd' are allocated their own columns. This flexibility in block sizing is crucial for accurately representing systems with components of varying significance or size.
|
||||
|
||||
### Creating Composite Blocks
|
||||
|
||||
#### Nested Blocks
|
||||
|
||||
Composite blocks, or blocks within blocks, are an advanced feature in Mermaid's block diagram syntax. They allow for the representation of nested or hierarchical systems, where one component encompasses several subcomponents.
|
||||
|
||||
**Example - Composite Blocks:**
|
||||
Creating a composite block involves defining a parent block and then nesting other blocks within it. Here's how to define a composite block with nested elements:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
D
|
||||
end
|
||||
A["A: I am a wide one"]
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
D
|
||||
end
|
||||
A["A: I am a wide one"]
|
||||
```
|
||||
|
||||
In this syntax, 'D' is a nested block within a larger parent block. This feature is particularly useful for depicting complex structures, such as a server with multiple services or a department within a larger organizational framework.
|
||||
|
||||
### Column Width Dynamics
|
||||
|
||||
#### Adjusting Widths
|
||||
|
||||
Mermaid also allows for dynamic adjustment of column widths based on the content of the blocks. The width of the columns is determined by the widest block in the column, ensuring that the diagram remains balanced and readable.
|
||||
|
||||
**Example - Dynamic Column Widths:**
|
||||
In diagrams with varying block sizes, Mermaid automatically adjusts the column widths to fit the largest block in each column. Here's an example:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
columns 3
|
||||
a:3
|
||||
block:group1:2
|
||||
columns 2
|
||||
h i j k
|
||||
end
|
||||
g
|
||||
block:group2:3
|
||||
%% columns auto (default)
|
||||
l m n o p q r
|
||||
end
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 3
|
||||
a:3
|
||||
block:group1:2
|
||||
columns 2
|
||||
h i j k
|
||||
end
|
||||
g
|
||||
block:group2:3
|
||||
%% columns auto (default)
|
||||
l m n o p q r
|
||||
end
|
||||
```
|
||||
|
||||
This example demonstrates how Mermaid dynamically adjusts the width of the columns to accommodate the widest block, in this case, 'a' and the composite block 'e'. This dynamic adjustment is essential for creating visually balanced and easy-to-understand diagrams.
|
||||
|
||||
With these advanced configuration options, Mermaid's block diagrams can be tailored to represent a wide array of complex systems and structures. The flexibility offered by these features enables users to create diagrams that are both informative and visually appealing. In the following sections, we will explore further capabilities, including different block shapes and linking options.
|
||||
|
||||
## 4. Block Varieties and Shapes
|
||||
|
||||
Mermaid's block diagrams are not limited to standard rectangular shapes. A variety of block shapes are available, allowing for a more nuanced and tailored representation of different types of information or entities. This section outlines the different block shapes you can use in Mermaid and their specific applications.
|
||||
|
||||
### Standard and Special Block Shapes
|
||||
|
||||
Mermaid supports a range of block shapes to suit different diagramming needs, from basic geometric shapes to more specialized forms.
|
||||
|
||||
#### Example - Round Edged Block
|
||||
|
||||
To create a block with round edges, which can be used to represent a softer or more flexible component:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
id1("This is the text in the box")
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
id1("This is the text in the box")
|
||||
```
|
||||
|
||||
#### Example - Stadium-Shaped Block
|
||||
|
||||
A stadium-shaped block, resembling an elongated circle, can be used for components that are process-oriented:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
id1(["This is the text in the box"])
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
id1(["This is the text in the box"])
|
||||
```
|
||||
|
||||
#### Example - Subroutine Shape
|
||||
|
||||
For representing subroutines or contained processes, a block with double vertical lines is useful:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
id1[["This is the text in the box"]]
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
id1[["This is the text in the box"]]
|
||||
```
|
||||
|
||||
#### Example - Cylindrical Shape
|
||||
|
||||
The cylindrical shape is ideal for representing databases or storage components:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
id1[("Database")]
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
id1[("Database")]
|
||||
```
|
||||
|
||||
#### Example - Circle Shape
|
||||
|
||||
A circle can be used for centralized or pivotal components:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
id1(("This is the text in the circle"))
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
id1(("This is the text in the circle"))
|
||||
```
|
||||
|
||||
#### Example - Asymmetric, Rhombus, and Hexagon Shapes
|
||||
|
||||
For decision points, use a rhombus, and for unique or specialized processes, asymmetric and hexagon shapes can be utilized:
|
||||
|
||||
**Asymmetric**
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
id1>"This is the text in the box"]
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
id1>"This is the text in the box"]
|
||||
```
|
||||
|
||||
**Rhombus**
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
id1{"This is the text in the box"}
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
id1{"This is the text in the box"}
|
||||
```
|
||||
|
||||
**Hexagon**
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
id1{{"This is the text in the box"}}
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
id1{{"This is the text in the box"}}
|
||||
```
|
||||
|
||||
#### Example - Parallelogram and Trapezoid Shapes
|
||||
|
||||
Parallelogram and trapezoid shapes are perfect for inputs/outputs and transitional processes:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
id1[/"This is the text in the box"/]
|
||||
id2[\"This is the text in the box"\]
|
||||
A[/"Christmas"\]
|
||||
B[\"Go shopping"/]
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
id1[/"This is the text in the box"/]
|
||||
id2[\"This is the text in the box"\]
|
||||
A[/"Christmas"\]
|
||||
B[\"Go shopping"/]
|
||||
```
|
||||
|
||||
#### Example - Double Circle
|
||||
|
||||
For highlighting critical or high-priority components, a double circle can be effective:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
id1((("This is the text in the circle")))
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
id1((("This is the text in the circle")))
|
||||
```
|
||||
|
||||
### Block Arrows and Space Blocks
|
||||
|
||||
Mermaid also offers unique shapes like block arrows and space blocks for directional flow and spacing.
|
||||
|
||||
#### Example - Block Arrows
|
||||
|
||||
Block arrows can visually indicate direction or flow within a process:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
blockArrowId<["Label"]>(right)
|
||||
blockArrowId2<["Label"]>(left)
|
||||
blockArrowId3<["Label"]>(up)
|
||||
blockArrowId4<["Label"]>(down)
|
||||
blockArrowId5<["Label"]>(x)
|
||||
blockArrowId6<["Label"]>(y)
|
||||
blockArrowId6<["Label"]>(x, down)
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
blockArrowId<["Label"]>(right)
|
||||
blockArrowId2<["Label"]>(left)
|
||||
blockArrowId3<["Label"]>(up)
|
||||
blockArrowId4<["Label"]>(down)
|
||||
blockArrowId5<["Label"]>(x)
|
||||
blockArrowId6<["Label"]>(y)
|
||||
blockArrowId6<["Label"]>(x, down)
|
||||
```
|
||||
|
||||
#### Example - Space Blocks
|
||||
|
||||
Space blocks can be used to create intentional empty spaces in the diagram, which is useful for layout and readability:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
columns 3
|
||||
a space b
|
||||
c d e
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 3
|
||||
a space b
|
||||
c d e
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
ida space:3 idb idc
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
ida space:3 idb idc
|
||||
```
|
||||
|
||||
Note that you can set how many columns the space block occupied using the number notation `space:num` where num is a number indicating the num columns width. You can also use `space` which defaults to one column.
|
||||
|
||||
The variety of shapes and special blocks in Mermaid enhances the expressive power of block diagrams, allowing for more accurate and context-specific representations. These options give users the flexibility to create diagrams that are both informative and visually appealing. In the next sections, we will explore the ways to connect these blocks and customize their appearance.
|
||||
|
||||
### Standard and Special Block Shapes
|
||||
|
||||
Discuss the various shapes available for blocks, including standard shapes and special forms like block arrows and space blocks.
|
||||
|
||||
## 5. Connecting Blocks with Edges
|
||||
|
||||
One of the key features of block diagrams in Mermaid is the ability to connect blocks using various types of edges or links. This section explores the different ways blocks can be interconnected to represent relationships and flows between components.
|
||||
|
||||
### Basic Linking and Arrow Types
|
||||
|
||||
The most fundamental aspect of connecting blocks is the use of arrows or links. These connectors depict the relationships or the flow of information between the blocks. Mermaid offers a range of arrow types to suit different diagramming needs.
|
||||
|
||||
**Example - Basic Links**
|
||||
|
||||
A simple link with an arrow can be created to show direction or flow from one block to another:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
A space B
|
||||
A-->B
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
A space B
|
||||
A-->B
|
||||
```
|
||||
|
||||
This example illustrates a direct connection from block 'A' to block 'B', using a straightforward arrow.
|
||||
|
||||
This syntax creates a line connecting 'A' and 'B', implying a relationship or connection without indicating a specific direction.
|
||||
|
||||
### Text on Links
|
||||
|
||||
In addition to connecting blocks, it's often necessary to describe or label the relationship. Mermaid allows for the inclusion of text on links, providing context to the connections.
|
||||
|
||||
Example - Text with Links
|
||||
To add text to a link, the syntax includes the text within the link definition:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
A space:2 B
|
||||
A-- "X" -->B
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
A space:2 B
|
||||
A-- "X" -->B
|
||||
```
|
||||
|
||||
This example show how to add descriptive text to the links, enhancing the information conveyed by the diagram.
|
||||
|
||||
Example - Edges and Styles:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
columns 1
|
||||
db(("DB"))
|
||||
blockArrowId6<[" "]>(down)
|
||||
block:ID
|
||||
A
|
||||
B["A wide one in the middle"]
|
||||
C
|
||||
end
|
||||
space
|
||||
D
|
||||
ID --> D
|
||||
C --> D
|
||||
style B fill:#939,stroke:#333,stroke-width:4px
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 1
|
||||
db(("DB"))
|
||||
blockArrowId6<[" "]>(down)
|
||||
block:ID
|
||||
A
|
||||
B["A wide one in the middle"]
|
||||
C
|
||||
end
|
||||
space
|
||||
D
|
||||
ID --> D
|
||||
C --> D
|
||||
style B fill:#939,stroke:#333,stroke-width:4px
|
||||
```
|
||||
|
||||
## 6. Styling and Customization
|
||||
|
||||
Beyond the structure and layout of block diagrams, Mermaid offers extensive styling options. These customization features allow for the creation of more visually distinctive and informative diagrams. This section covers how to apply individual styles to blocks and how to use classes for consistent styling across multiple elements.
|
||||
|
||||
### Individual Block Styling
|
||||
|
||||
Mermaid enables detailed styling of individual blocks, allowing you to apply various CSS properties such as color, stroke, and border thickness. This feature is especially useful for highlighting specific parts of a diagram or for adhering to certain visual themes.
|
||||
|
||||
#### Example - Styling a Single Block
|
||||
|
||||
To apply custom styles to a block, you can use the `style` keyword followed by the block identifier and the desired CSS properties:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
id1 space id2
|
||||
id1("Start")-->id2("Stop")
|
||||
style id1 fill:#636,stroke:#333,stroke-width:4px
|
||||
style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
id1 space id2
|
||||
id1("Start")-->id2("Stop")
|
||||
style id1 fill:#636,stroke:#333,stroke-width:4px
|
||||
style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
|
||||
```
|
||||
|
||||
In this example, a class named 'blue' is defined and applied to block 'A', while block 'B' receives individual styling. This demonstrates the flexibility of Mermaid in applying both shared and unique styles within the same diagram.
|
||||
|
||||
The ability to style blocks individually or through classes provides a powerful tool for enhancing the visual impact and clarity of block diagrams. Whether emphasizing certain elements or maintaining a cohesive design across the diagram, these styling capabilities are central to effective diagramming. The next sections will present practical examples and use cases, followed by tips for troubleshooting common issues.
|
||||
|
||||
### 7. Practical Examples and Use Cases
|
||||
|
||||
The versatility of Mermaid's block diagrams becomes evident when applied to real-world scenarios. This section provides practical examples demonstrating the application of various features discussed in previous sections. These examples showcase how block diagrams can be used to represent complex systems and processes in an accessible and informative manner.
|
||||
|
||||
### Detailed Examples Illustrating Various Features
|
||||
|
||||
Combining the elements of structure, linking, and styling, we can create comprehensive diagrams that serve specific purposes in different contexts.
|
||||
|
||||
#### Example - System Architecture
|
||||
|
||||
Illustrating a simple software system architecture with interconnected components:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
columns 3
|
||||
Frontend blockArrowId6<[" "]>(right) Backend
|
||||
space:2 down<[" "]>(down)
|
||||
Disk left<[" "]>(left) Database[("Database")]
|
||||
|
||||
classDef front fill:#696,stroke:#333;
|
||||
classDef back fill:#969,stroke:#333;
|
||||
class Frontend front
|
||||
class Backend,Database back
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 3
|
||||
Frontend blockArrowId6<[" "]>(right) Backend
|
||||
space:2 down<[" "]>(down)
|
||||
Disk left<[" "]>(left) Database[("Database")]
|
||||
|
||||
classDef front fill:#696,stroke:#333;
|
||||
classDef back fill:#969,stroke:#333;
|
||||
class Frontend front
|
||||
class Backend,Database back
|
||||
```
|
||||
|
||||
This example shows a basic architecture with a frontend, backend, and database. The blocks are styled to differentiate between types of components.
|
||||
|
||||
#### Example - Business Process Flow
|
||||
|
||||
Representing a business process flow with decision points and multiple stages:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
columns 3
|
||||
Start(("Start")) space:2
|
||||
down<[" "]>(down) space:2
|
||||
Decision{{"Make Decision"}} right<["Yes"]>(right) Process1["Process A"]
|
||||
downAgain<["No"]>(down) space r3<["Done"]>(down)
|
||||
Process2["Process B"] r2<["Done"]>(right) End(("End"))
|
||||
|
||||
style Start fill:#969;
|
||||
style End fill:#696;
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 3
|
||||
Start(("Start")) space:2
|
||||
down<[" "]>(down) space:2
|
||||
Decision{{"Make Decision"}} right<["Yes"]>(right) Process1["Process A"]
|
||||
downAgain<["No"]>(down) space r3<["Done"]>(down)
|
||||
Process2["Process B"] r2<["Done"]>(right) End(("End"))
|
||||
|
||||
style Start fill:#969;
|
||||
style End fill:#696;
|
||||
```
|
||||
|
||||
These practical examples and scenarios underscore the utility of Mermaid block diagrams in simplifying and effectively communicating complex information across various domains.
|
||||
|
||||
The next section, 'Troubleshooting and Common Issues', will provide insights into resolving common challenges encountered when working with Mermaid block diagrams, ensuring a smooth diagramming experience.
|
||||
|
||||
## 8. Troubleshooting and Common Issues
|
||||
|
||||
Working with Mermaid block diagrams can sometimes present challenges, especially as the complexity of the diagrams increases. This section aims to provide guidance on resolving common issues and offers tips for managing more intricate diagram structures.
|
||||
|
||||
### Common Syntax Errors
|
||||
|
||||
Understanding and avoiding common syntax errors is key to a smooth experience with Mermaid diagrams.
|
||||
|
||||
#### Example - Incorrect Linking
|
||||
|
||||
A common mistake is incorrect linking syntax, which can lead to unexpected results or broken diagrams:
|
||||
|
||||
block-beta
|
||||
A - B
|
||||
|
||||
**Correction**:
|
||||
Ensure that links between blocks are correctly specified with arrows (--> or ---) to define the direction and type of connection. Also remember that one of the fundaments for block diagram is to give the author full control of where the boxes are positioned so in the example you need to add a space between the boxes:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
A space B
|
||||
A --> B
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
A space B
|
||||
A --> B
|
||||
```
|
||||
|
||||
#### Example - Misplaced Styling
|
||||
|
||||
Applying styles in the wrong context or with incorrect syntax can lead to blocks not being styled as intended:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
A
|
||||
style A fill#969;
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
A
|
||||
style A fill#969;
|
||||
```
|
||||
|
||||
**Correction:**
|
||||
Correct the syntax by ensuring proper separation of style properties with commas and using the correct CSS property format:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
A
|
||||
style A fill:#969,stroke:#333;
|
||||
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
A
|
||||
style A fill:#969,stroke:#333;
|
||||
|
||||
```
|
||||
|
||||
### Tips for Complex Diagram Structures
|
||||
|
||||
Managing complexity in Mermaid diagrams involves planning and employing best practices.
|
||||
|
||||
#### Modular Design
|
||||
|
||||
Break down complex diagrams into smaller, more manageable components. This approach not only makes the diagram easier to understand but also simplifies the creation and maintenance process.
|
||||
|
||||
#### Consistent Styling
|
||||
|
||||
Use classes to maintain consistent styling across similar elements. This not only saves time but also ensures a cohesive and professional appearance.
|
||||
|
||||
#### Comments and Documentation
|
||||
|
||||
Use comments with `%%` within the Mermaid syntax to document the purpose of various parts of the diagram. This practice is invaluable for maintaining clarity, especially when working in teams or returning to a diagram after some time.
|
||||
|
||||
With these troubleshooting tips and best practices, you can effectively manage and resolve common issues in Mermaid block diagrams. The final section, 'Conclusion', will summarize the key points covered in this documentation and invite user feedback for continuous improvement.
|
@ -191,7 +191,7 @@ The following unfinished features are not supported in the short term.
|
||||
- [x] Rel_L, Rel_Left
|
||||
- [x] Rel_R, Rel_Right
|
||||
- [x] Rel_Back
|
||||
- [x] RelIndex \* Compatible with C4-Plantuml syntax, but ignores the index parameter. The sequence number is determined by the order in which the rel statements are written.
|
||||
- [x] RelIndex \* Compatible with C4-PlantUML syntax, but ignores the index parameter. The sequence number is determined by the order in which the rel statements are written.
|
||||
|
||||
- [ ] Custom tags/stereotypes support and skin param updates
|
||||
- [ ] AddElementTag(tagStereo, ?bgColor, ?fontColor, ?borderColor, ?shadowing, ?shape, ?sprite, ?techn, ?legendText, ?legendSprite): Introduces a new element tag. The styles of the tagged elements are updated and the tag is displayed in the calculated legend.
|
||||
@ -320,7 +320,7 @@ UpdateRelStyle(customerA, bankA, $offsetY="60")
|
||||
Person(customer, Customer, "A customer of the bank, with personal bank accounts", $tags="v1.0")
|
||||
|
||||
Container_Boundary(c1, "Internet Banking") {
|
||||
Container(spa, "Single-Page App", "JavaScript, Angular", "Provides all the Internet banking functionality to cutomers via their web browser")
|
||||
Container(spa, "Single-Page App", "JavaScript, Angular", "Provides all the Internet banking functionality to customers via their web browser")
|
||||
Container_Ext(mobile_app, "Mobile App", "C#, Xamarin", "Provides a limited subset of the Internet banking functionality to customers via their mobile device")
|
||||
Container(web_app, "Web Application", "Java, Spring MVC", "Delivers the static content and the Internet banking SPA")
|
||||
ContainerDb(database, "Database", "SQL Database", "Stores user registration information, hashed auth credentials, access logs, etc.")
|
||||
@ -360,7 +360,7 @@ UpdateRelStyle(customerA, bankA, $offsetY="60")
|
||||
Person(customer, Customer, "A customer of the bank, with personal bank accounts", $tags="v1.0")
|
||||
|
||||
Container_Boundary(c1, "Internet Banking") {
|
||||
Container(spa, "Single-Page App", "JavaScript, Angular", "Provides all the Internet banking functionality to cutomers via their web browser")
|
||||
Container(spa, "Single-Page App", "JavaScript, Angular", "Provides all the Internet banking functionality to customers via their web browser")
|
||||
Container_Ext(mobile_app, "Mobile App", "C#, Xamarin", "Provides a limited subset of the Internet banking functionality to customers via their mobile device")
|
||||
Container(web_app, "Web Application", "Java, Spring MVC", "Delivers the static content and the Internet banking SPA")
|
||||
ContainerDb(database, "Database", "SQL Database", "Stores user registration information, hashed auth credentials, access logs, etc.")
|
||||
@ -621,3 +621,5 @@ UpdateRelStyle(customerA, bankA, $offsetY="60")
|
||||
UpdateRelStyle(db, db2, $offsetY="-10")
|
||||
|
||||
```
|
||||
|
||||
<!--- cspell:ignore bigbank bigbankdb techn mbsfacade --->
|
||||
|
@ -240,7 +240,7 @@ class BankAccount{
|
||||
|
||||
#### Generic Types
|
||||
|
||||
Generics can be representated as part of a class definition, and for class members/return types. In order to denote an item as generic, you enclose that type within `~` (**tilde**). **Nested** type declarations such as `List<List<int>>` are supported, though generics that include a comma are currently not supported. (such as `List<List<K, V>>`)
|
||||
Generics can be represented as part of a class definition, and for class members/return types. In order to denote an item as generic, you enclose that type within `~` (**tilde**). **Nested** type declarations such as `List<List<int>>` are supported, though generics that include a comma are currently not supported. (such as `List<List<K, V>>`)
|
||||
|
||||
> _note_ when a generic is used within a class definition, the generic type is NOT considered part of the class name. i.e.: for any syntax which required you to reference the class name, you need to drop the type part of the definition. This also means that mermaid does not currently support having two classes with the same name, but different generic types.
|
||||
|
||||
|
@ -307,3 +307,5 @@ The following CSS class selectors are available for richer styling:
|
||||
| `.er.relationshipLabel` | The label for a relationship |
|
||||
| `.er.relationshipLabelBox` | The box surrounding a relationship label |
|
||||
| `.er.relationshipLine` | The line representing a relationship between entities |
|
||||
|
||||
<!--- cspell:locale en,en-gb --->
|
||||
|
@ -175,7 +175,7 @@ sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice->>John: Hello John, how are you?
|
||||
loop Healthcheck
|
||||
loop HealthCheck
|
||||
John->>John: Fight against hypochondria
|
||||
end
|
||||
Note right of John: Rational thoughts<br/>prevail...
|
||||
@ -189,7 +189,7 @@ sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice->>John: Hello John, how are you?
|
||||
loop Healthcheck
|
||||
loop HealthCheck
|
||||
John->>John: Fight against hypochondria
|
||||
end
|
||||
Note right of John: Rational thoughts<br/>prevail...
|
||||
@ -297,3 +297,5 @@ gitGraph:
|
||||
branch b2
|
||||
commit
|
||||
```
|
||||
|
||||
<!--- cspell:ignore Ashish newbranch --->
|
||||
|
@ -1200,3 +1200,5 @@ mermaid.flowchartConfig = {
|
||||
width: 100%
|
||||
}
|
||||
```
|
||||
|
||||
<!--- cspell:ignore lagom --->
|
||||
|
@ -294,11 +294,11 @@ gantt
|
||||
weekday monday
|
||||
```
|
||||
|
||||
> **Warning** > `millisecond` and `second` support was added in vMERMAID_RELEASE_VERSION
|
||||
> **Warning** > `millisecond` and `second` support was added in v10.3.0
|
||||
|
||||
## Output in compact mode
|
||||
|
||||
The compact mode allows you to display multiple tasks in the same row. Compact mode can be enabled for a gantt chart by setting the display mode of the graph via preceeding YAML settings.
|
||||
The compact mode allows you to display multiple tasks in the same row. Compact mode can be enabled for a gantt chart by setting the display mode of the graph via preceding YAML settings.
|
||||
|
||||
```mermaid-example
|
||||
---
|
||||
|
@ -419,6 +419,7 @@ In Mermaid, you have the option to configure the gitgraph diagram. You can confi
|
||||
- `showCommitLabel` : Boolean, default is `true`. If set to `false`, the commit labels are not shown in the diagram.
|
||||
- `mainBranchName` : String, default is `main`. The name of the default/root branch.
|
||||
- `mainBranchOrder` : Position of the main branch in the list of branches. default is `0`, meaning, by default `main` branch is the first in the order.
|
||||
- `parallelCommits`: Boolean, default is `false`. If set to `true`, commits x distance away from the parent are shown at the same level in the diagram.
|
||||
|
||||
Let's look at them one by one.
|
||||
|
||||
@ -915,6 +916,78 @@ Usage example:
|
||||
commit
|
||||
```
|
||||
|
||||
## Parallel commits (v10.8.0+)
|
||||
|
||||
Commits in Mermaid display temporal information in gitgraph by default. For example if two commits are one commit away from its parent, the commit that was made earlier is rendered closer to its parent. You can turn this off by enabling the `parallelCommits` flag.
|
||||
|
||||
### Temporal Commits (default, `parallelCommits: false`)
|
||||
|
||||
```mermaid-example
|
||||
---
|
||||
config:
|
||||
gitGraph:
|
||||
parallelCommits: false
|
||||
---
|
||||
gitGraph:
|
||||
commit
|
||||
branch develop
|
||||
commit
|
||||
commit
|
||||
checkout main
|
||||
commit
|
||||
commit
|
||||
```
|
||||
|
||||
```mermaid
|
||||
---
|
||||
config:
|
||||
gitGraph:
|
||||
parallelCommits: false
|
||||
---
|
||||
gitGraph:
|
||||
commit
|
||||
branch develop
|
||||
commit
|
||||
commit
|
||||
checkout main
|
||||
commit
|
||||
commit
|
||||
```
|
||||
|
||||
### Parallel commits (`parallelCommits: true`)
|
||||
|
||||
```mermaid-example
|
||||
---
|
||||
config:
|
||||
gitGraph:
|
||||
parallelCommits: true
|
||||
---
|
||||
gitGraph:
|
||||
commit
|
||||
branch develop
|
||||
commit
|
||||
commit
|
||||
checkout main
|
||||
commit
|
||||
commit
|
||||
```
|
||||
|
||||
```mermaid
|
||||
---
|
||||
config:
|
||||
gitGraph:
|
||||
parallelCommits: true
|
||||
---
|
||||
gitGraph:
|
||||
commit
|
||||
branch develop
|
||||
commit
|
||||
commit
|
||||
checkout main
|
||||
commit
|
||||
commit
|
||||
```
|
||||
|
||||
## Themes
|
||||
|
||||
Mermaid supports a bunch of pre-defined themes which you can use to find the right one for you. PS: you can actually override an existing theme's variable to get your own custom theme going. Learn more about theming your diagram [here](../config/theming.md).
|
||||
@ -1626,7 +1699,7 @@ See how the commit label color and background color are changed to the values sp
|
||||
|
||||
### Customizing Commit Label Font Size
|
||||
|
||||
You can customize commit using the `commitLabelFontSize` theme variables for changing in the font soze of the commit label .
|
||||
You can customize commit using the `commitLabelFontSize` theme variables for changing in the font size of the commit label .
|
||||
|
||||
Example:
|
||||
Now let's override the default values for the `commitLabelFontSize` variable:
|
||||
@ -1677,7 +1750,7 @@ See how the commit label font size changed.
|
||||
|
||||
### Customizing Tag Label Font Size
|
||||
|
||||
You can customize commit using the `tagLabelFontSize` theme variables for changing in the font soze of the tag label .
|
||||
You can customize commit using the `tagLabelFontSize` theme variables for changing in the font size of the tag label .
|
||||
|
||||
Example:
|
||||
Now let's override the default values for the `tagLabelFontSize` variable:
|
||||
|
@ -305,3 +305,8 @@ From version 9.4.0 you can simplify this code to:
|
||||
```
|
||||
|
||||
You can also refer the implementation in the live editor [here](https://github.com/mermaid-js/mermaid-live-editor/blob/develop/src/lib/util/mermaid.ts) to see how the async loading is done.
|
||||
|
||||
<!---
|
||||
cspell:locale en,en-gb
|
||||
cspell:ignore Buzan
|
||||
--->
|
||||
|
@ -241,3 +241,5 @@ This example uses all features of the diagram.
|
||||
test_entity3 - verifies -> test_req5
|
||||
test_req <- copies - test_entity2
|
||||
```
|
||||
|
||||
<!--- cspell:ignore reqs --->
|
||||
|
@ -301,3 +301,5 @@ Graph layout can be changed by setting `nodeAlignment` to:
|
||||
- `center`
|
||||
- `left`
|
||||
- `right`
|
||||
|
||||
<!--- cspell:ignore Ngas bioenergy biofuel --->
|
||||
|
@ -172,8 +172,8 @@ The actor(s) can be grouped in vertical boxes. You can define a color (if not, i
|
||||
end
|
||||
A->>J: Hello John, how are you?
|
||||
J->>A: Great!
|
||||
A->>B: Hello Bob, how is Charly?
|
||||
B->>C: Hello Charly, how are you?
|
||||
A->>B: Hello Bob, how is Charley?
|
||||
B->>C: Hello Charley, how are you?
|
||||
```
|
||||
|
||||
```mermaid
|
||||
@ -188,8 +188,8 @@ The actor(s) can be grouped in vertical boxes. You can define a color (if not, i
|
||||
end
|
||||
A->>J: Hello John, how are you?
|
||||
J->>A: Great!
|
||||
A->>B: Hello Bob, how is Charly?
|
||||
B->>C: Hello Charly, how are you?
|
||||
A->>B: Hello Bob, how is Charley?
|
||||
B->>C: Hello Charley, how are you?
|
||||
```
|
||||
|
||||
## Messages
|
||||
@ -646,7 +646,7 @@ It can also be turned on via the diagram code as in the diagram:
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
Alice->>John: Hello John, how are you?
|
||||
loop Healthcheck
|
||||
loop HealthCheck
|
||||
John->>John: Fight against hypochondria
|
||||
end
|
||||
Note right of John: Rational thoughts!
|
||||
@ -659,7 +659,7 @@ sequenceDiagram
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
Alice->>John: Hello John, how are you?
|
||||
loop Healthcheck
|
||||
loop HealthCheck
|
||||
John->>John: Fight against hypochondria
|
||||
end
|
||||
Note right of John: Rational thoughts!
|
||||
@ -740,20 +740,22 @@ Styling of a sequence diagram is done by defining a number of css classes. Durin
|
||||
|
||||
### Classes used
|
||||
|
||||
| Class | Description |
|
||||
| ------------ | ----------------------------------------------------------- |
|
||||
| actor | Style for the actor box at the top of the diagram. |
|
||||
| text.actor | Styles for text in the actor box at the top of the diagram. |
|
||||
| actor-line | The vertical line for an actor. |
|
||||
| messageLine0 | Styles for the solid message line. |
|
||||
| messageLine1 | Styles for the dotted message line. |
|
||||
| messageText | Defines styles for the text on the message arrows. |
|
||||
| labelBox | Defines styles label to left in a loop. |
|
||||
| labelText | Styles for the text in label for loops. |
|
||||
| loopText | Styles for the text in the loop box. |
|
||||
| loopLine | Defines styles for the lines in the loop box. |
|
||||
| note | Styles for the note box. |
|
||||
| noteText | Styles for the text on in the note boxes. |
|
||||
| Class | Description |
|
||||
| ------------ | -------------------------------------------------------------- |
|
||||
| actor | Styles for the actor box. |
|
||||
| actor-top | Styles for the actor figure/ box at the top of the diagram. |
|
||||
| actor-bottom | Styles for the actor figure/ box at the bottom of the diagram. |
|
||||
| text.actor | Styles for text in the actor box. |
|
||||
| actor-line | The vertical line for an actor. |
|
||||
| messageLine0 | Styles for the solid message line. |
|
||||
| messageLine1 | Styles for the dotted message line. |
|
||||
| messageText | Defines styles for the text on the message arrows. |
|
||||
| labelBox | Defines styles label to left in a loop. |
|
||||
| labelText | Styles for the text in label for loops. |
|
||||
| loopText | Styles for the text in the loop box. |
|
||||
| loopLine | Defines styles for the lines in the loop box. |
|
||||
| note | Styles for the note box. |
|
||||
| noteText | Styles for the text on in the note boxes. |
|
||||
|
||||
### Sample stylesheet
|
||||
|
||||
|
@ -622,7 +622,7 @@ Spaces can be added to a state by first defining the state with an id and then r
|
||||
|
||||
In the following example there is a state with the id **yswsii** and description **Your state with spaces in it**.
|
||||
After it has been defined, **yswsii** is used in the diagram in the first transition (`[*] --> yswsii`)
|
||||
and also in the transition to **YetAnotherState** (`yswsii --> YetAnotherState`).\
|
||||
and also in the transition to **YetAnotherState** (`yswsii --> YetAnotherState`).
|
||||
(**yswsii** has been styled so that it is different from the other states.)
|
||||
|
||||
```mermaid-example
|
||||
@ -648,3 +648,5 @@ stateDiagram
|
||||
yswsii --> YetAnotherState
|
||||
YetAnotherState --> [*]
|
||||
```
|
||||
|
||||
<!--- cspell:ignore yswsii --->
|
||||
|
@ -8,9 +8,9 @@
|
||||
|
||||
> Timeline: This is an experimental diagram for now. The syntax and properties can change in future releases. The syntax is stable except for the icon integration which is the experimental part.
|
||||
|
||||
"A timeline is a type of diagram used to illustrate a chronology of events, dates, or periods of time. It is usually presented graphically to indicate the passing of time, and it is usually organized chronologically. A basic timeline presents a list of events in chronological order, usually using dates as markers. A timeline can also be used to show the relationship between events, such as the relationship between the events of a person's life." Wikipedia
|
||||
"A timeline is a type of diagram used to illustrate a chronology of events, dates, or periods of time. It is usually presented graphically to indicate the passing of time, and it is usually organized chronologically. A basic timeline presents a list of events in chronological order, usually using dates as markers. A timeline can also be used to show the relationship between events, such as the relationship between the events of a person's life" [(Wikipedia)](https://en.wikipedia.org/wiki/Timeline).
|
||||
|
||||
### An example of a timeline.
|
||||
### An example of a timeline
|
||||
|
||||
```mermaid-example
|
||||
timeline
|
||||
@ -58,7 +58,7 @@ or
|
||||
: {event}
|
||||
```
|
||||
|
||||
NOTE: Both time period and event are simple text, and not limited to numbers.
|
||||
**NOTE**: Both time period and event are simple text, and not limited to numbers.
|
||||
|
||||
Let us look at the syntax for the example above.
|
||||
|
||||
@ -104,7 +104,7 @@ timeline
|
||||
Industry 3.0 : Electronics, Computers, Automation
|
||||
section 21st century
|
||||
Industry 4.0 : Internet, Robotics, Internet of Things
|
||||
Industry 5.0 : Artificial intelligence, Big data,3D printing
|
||||
Industry 5.0 : Artificial intelligence, Big data, 3D printing
|
||||
```
|
||||
|
||||
```mermaid
|
||||
@ -116,7 +116,7 @@ timeline
|
||||
Industry 3.0 : Electronics, Computers, Automation
|
||||
section 21st century
|
||||
Industry 4.0 : Internet, Robotics, Internet of Things
|
||||
Industry 5.0 : Artificial intelligence, Big data,3D printing
|
||||
Industry 5.0 : Artificial intelligence, Big data, 3D printing
|
||||
```
|
||||
|
||||
As you can see, the time periods are placed in the sections, and the sections are placed in the order they are defined.
|
||||
@ -163,11 +163,11 @@ timeline
|
||||
timeline
|
||||
title MermaidChart 2023 Timeline
|
||||
section 2023 Q1 <br> Release Personal Tier
|
||||
Buttet 1 : sub-point 1a : sub-point 1b
|
||||
Bullet 1 : sub-point 1a : sub-point 1b
|
||||
: sub-point 1c
|
||||
Bullet 2 : sub-point 2a : sub-point 2b
|
||||
section 2023 Q2 <br> Release XYZ Tier
|
||||
Buttet 3 : sub-point <br> 3a : sub-point 3b
|
||||
Bullet 3 : sub-point <br> 3a : sub-point 3b
|
||||
: sub-point 3c
|
||||
Bullet 4 : sub-point 4a : sub-point 4b
|
||||
```
|
||||
@ -176,11 +176,11 @@ timeline
|
||||
timeline
|
||||
title MermaidChart 2023 Timeline
|
||||
section 2023 Q1 <br> Release Personal Tier
|
||||
Buttet 1 : sub-point 1a : sub-point 1b
|
||||
Bullet 1 : sub-point 1a : sub-point 1b
|
||||
: sub-point 1c
|
||||
Bullet 2 : sub-point 2a : sub-point 2b
|
||||
section 2023 Q2 <br> Release XYZ Tier
|
||||
Buttet 3 : sub-point <br> 3a : sub-point 3b
|
||||
Bullet 3 : sub-point <br> 3a : sub-point 3b
|
||||
: sub-point 3c
|
||||
Bullet 4 : sub-point 4a : sub-point 4b
|
||||
```
|
||||
@ -191,7 +191,7 @@ As explained earlier, each section has a color scheme, and each time period and
|
||||
|
||||
However, if there is no section defined, then we have two possibilities:
|
||||
|
||||
1. Style time periods individually, i.e. each time period(and its coressponding events) will have its own color scheme. This is the DEFAULT behavior.
|
||||
1. Style time periods individually, i.e. each time period(and its corresponding events) will have its own color scheme. This is the DEFAULT behavior.
|
||||
|
||||
```mermaid-example
|
||||
timeline
|
||||
@ -213,7 +213,7 @@ However, if there is no section defined, then we have two possibilities:
|
||||
|
||||
```
|
||||
|
||||
Note that there are no sections defined, and each time period and its corresponding events will have its own color scheme.
|
||||
**NOTE**: that there are no sections defined, and each time period and its corresponding events will have its own color scheme.
|
||||
|
||||
2. Disable the multiColor option using the `disableMultiColor` option. This will make all time periods and events follow the same color scheme.
|
||||
|
||||
@ -262,7 +262,7 @@ In case you have more than 12 sections, the color scheme will start to repeat.
|
||||
|
||||
If you also want to change the foreground color of a section, you can do so use theme variables corresponding `cScaleLabel0` to `cScaleLabel11` variables.
|
||||
|
||||
NOTE: Default values for these theme variables are picked from the selected theme. If you want to override the default values, you can use the `initialize` call to add your custom theme variable values.
|
||||
**NOTE**: Default values for these theme variables are picked from the selected theme. If you want to override the default values, you can use the `initialize` call to add your custom theme variable values.
|
||||
|
||||
Example:
|
||||
|
||||
@ -461,7 +461,7 @@ Let's put them to use, and see how our sample diagram looks in different themes:
|
||||
2010 : Pinterest
|
||||
```
|
||||
|
||||
## Integrating with your library/website.
|
||||
## Integrating with your library/website
|
||||
|
||||
Timeline uses experimental lazy loading & async rendering features which could change in the future.The lazy loading is important in order to be able to add additional diagrams going forward.
|
||||
|
||||
|
@ -139,11 +139,11 @@ The only two things required are the chart name (`xychart-beta`) and one data se
|
||||
| ---------------- | --------------------------------------------------------- |
|
||||
| backgroundColor | Background color of the whole chart |
|
||||
| titleColor | Color of the Title text |
|
||||
| xAxisLableColor | Color of the x-axis labels |
|
||||
| xAxisLabelColor | Color of the x-axis labels |
|
||||
| xAxisTitleColor | Color of the x-axis title |
|
||||
| xAxisTickColor | Color of the x-axis tick |
|
||||
| xAxisLineColor | Color of the x-axis line |
|
||||
| yAxisLableColor | Color of the y-axis labels |
|
||||
| yAxisLabelColor | Color of the y-axis labels |
|
||||
| yAxisTitleColor | Color of the y-axis title |
|
||||
| yAxisTickColor | Color of the y-axis tick |
|
||||
| yAxisLineColor | Color of the y-axis line |
|
||||
|
19
package.json
19
package.json
@ -4,7 +4,7 @@
|
||||
"version": "10.2.4",
|
||||
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
|
||||
"type": "module",
|
||||
"packageManager": "pnpm@8.14.1",
|
||||
"packageManager": "pnpm@8.15.1",
|
||||
"keywords": [
|
||||
"diagram",
|
||||
"markdown",
|
||||
@ -64,7 +64,7 @@
|
||||
"@applitools/eyes-cypress": "^3.40.6",
|
||||
"@commitlint/cli": "^17.6.1",
|
||||
"@commitlint/config-conventional": "^17.6.1",
|
||||
"@cspell/eslint-plugin": "^6.31.1",
|
||||
"@cspell/eslint-plugin": "^8.3.2",
|
||||
"@cypress/code-coverage": "^3.12.18",
|
||||
"@rollup/plugin-typescript": "^11.1.1",
|
||||
"@types/cors": "^2.8.13",
|
||||
@ -74,7 +74,7 @@
|
||||
"@types/jsdom": "^21.1.1",
|
||||
"@types/lodash": "^4.14.194",
|
||||
"@types/mdast": "^3.0.11",
|
||||
"@types/node": "^18.16.0",
|
||||
"@types/node": "^20.11.10",
|
||||
"@types/prettier": "^2.7.2",
|
||||
"@types/rollup-plugin-visualizer": "^4.2.1",
|
||||
"@typescript-eslint/eslint-plugin": "^6.7.2",
|
||||
@ -85,9 +85,10 @@
|
||||
"ajv": "^8.12.0",
|
||||
"concurrently": "^8.0.1",
|
||||
"cors": "^2.8.5",
|
||||
"cspell": "^8.3.2",
|
||||
"cypress": "^12.17.4",
|
||||
"cypress-image-snapshot": "^4.0.1",
|
||||
"esbuild": "^0.19.0",
|
||||
"esbuild": "^0.20.0",
|
||||
"eslint": "^8.47.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-cypress": "^2.13.2",
|
||||
@ -118,14 +119,16 @@
|
||||
"start-server-and-test": "^2.0.0",
|
||||
"tsx": "^4.6.2",
|
||||
"typescript": "^5.1.3",
|
||||
"vite": "^4.4.12",
|
||||
"vite": "^4.5.2",
|
||||
"vite-plugin-istanbul": "^4.1.0",
|
||||
"vitest": "^0.34.0"
|
||||
},
|
||||
"volta": {
|
||||
"node": "18.19.0"
|
||||
},
|
||||
"nyc": {
|
||||
"report-dir": "coverage/cypress"
|
||||
},
|
||||
"pnpm": {
|
||||
"patchedDependencies": {
|
||||
"cytoscape@3.28.1": "patches/cytoscape@3.28.1.patch"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,15 +39,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^6.0.1",
|
||||
"cytoscape": "^3.23.0",
|
||||
"cytoscape-cose-bilkent": "^4.1.0",
|
||||
"cytoscape-fcose": "^2.1.0",
|
||||
"d3": "^7.0.0",
|
||||
"khroma": "^2.0.0",
|
||||
"non-layered-tidy-tree-layout": "^2.0.2"
|
||||
"khroma": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cytoscape": "^3.19.9",
|
||||
"concurrently": "^8.0.0",
|
||||
"rimraf": "^5.0.0",
|
||||
"mermaid": "workspace:*"
|
||||
|
@ -33,7 +33,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@zenuml/core": "^3.0.6"
|
||||
"@zenuml/core": "^3.17.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mermaid": "workspace:^"
|
||||
|
@ -56,7 +56,7 @@ export const draw = async function (text: string, id: string) {
|
||||
// @ts-expect-error @zenuml/core@3.0.0 exports the wrong type for ZenUml
|
||||
const zenuml = new ZenUml(app);
|
||||
// default is a theme name. More themes to be added and will be configurable in the future
|
||||
await zenuml.render(text, 'theme-mermaid');
|
||||
await zenuml.render(text, { theme: 'default', mode: 'static' });
|
||||
|
||||
const { width, height } = window.getComputedStyle(container);
|
||||
log.debug('zenuml diagram size', width, height);
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mermaid",
|
||||
"version": "10.7.0",
|
||||
"version": "10.8.0",
|
||||
"description": "Markdown-ish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
|
||||
"type": "module",
|
||||
"module": "./dist/mermaid.core.mjs",
|
||||
@ -33,7 +33,7 @@
|
||||
"docs:dev": "pnpm docs:pre:vitepress && concurrently \"pnpm --filter ./src/vitepress dev\" \"tsx scripts/docs.cli.mts --watch --vitepress\"",
|
||||
"docs:dev:docker": "pnpm docs:pre:vitepress && concurrently \"pnpm --filter ./src/vitepress dev:docker\" \"tsx scripts/docs.cli.mts --watch --vitepress\"",
|
||||
"docs:serve": "pnpm docs:build:vitepress && vitepress serve src/vitepress",
|
||||
"docs:spellcheck": "cspell --config ../../cSpell.json \"src/docs/**/*.md\"",
|
||||
"docs:spellcheck": "cspell \"src/docs/**/*.md\"",
|
||||
"docs:release-version": "tsx scripts/update-release-version.mts",
|
||||
"docs:verify-version": "tsx scripts/update-release-version.mts --verify",
|
||||
"types:build-config": "tsx scripts/create-types-from-json-schema.mts",
|
||||
@ -62,15 +62,15 @@
|
||||
"@braintree/sanitize-url": "^6.0.1",
|
||||
"@types/d3-scale": "^4.0.3",
|
||||
"@types/d3-scale-chromatic": "^3.0.0",
|
||||
"cytoscape": "^3.23.0",
|
||||
"cytoscape": "^3.28.1",
|
||||
"cytoscape-cose-bilkent": "^4.1.0",
|
||||
"cytoscape-fcose": "^2.1.0",
|
||||
"d3": "^7.4.0",
|
||||
"d3-sankey": "^0.12.3",
|
||||
"dagre-d3-es": "7.0.10",
|
||||
"dayjs": "^1.11.7",
|
||||
"dompurify": "^3.0.5",
|
||||
"elkjs": "^0.9.0",
|
||||
"katex": "^0.16.9",
|
||||
"khroma": "^2.0.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"mdast-util-from-markdown": "^1.3.0",
|
||||
@ -90,6 +90,7 @@
|
||||
"@types/d3-shape": "^3.1.1",
|
||||
"@types/dompurify": "^3.0.2",
|
||||
"@types/jsdom": "^21.1.1",
|
||||
"@types/katex": "^0.16.7",
|
||||
"@types/lodash-es": "^4.17.7",
|
||||
"@types/micromatch": "^4.0.2",
|
||||
"@types/prettier": "^2.7.2",
|
||||
@ -101,7 +102,6 @@
|
||||
"chokidar": "^3.5.3",
|
||||
"concurrently": "^8.0.1",
|
||||
"cpy-cli": "^4.2.0",
|
||||
"cspell": "^6.31.1",
|
||||
"csstree-validator": "^3.0.0",
|
||||
"globby": "^13.1.4",
|
||||
"jison": "^0.4.18",
|
||||
@ -122,8 +122,8 @@
|
||||
"typescript": "^5.0.4",
|
||||
"unist-util-flatmap": "^1.0.0",
|
||||
"unist-util-visit": "^4.1.2",
|
||||
"vitepress": "^1.0.0-alpha.72",
|
||||
"vitepress-plugin-search": "^1.0.4-alpha.20"
|
||||
"vitepress": "^1.0.0-rc.40",
|
||||
"vitepress-plugin-search": "^1.0.4-alpha.22"
|
||||
},
|
||||
"files": [
|
||||
"dist/",
|
||||
|
@ -127,6 +127,14 @@ export interface MermaidConfig {
|
||||
*
|
||||
*/
|
||||
secure?: string[];
|
||||
/**
|
||||
* This option specifies if Mermaid can expect the dependent to include KaTeX stylesheets for browsers
|
||||
* without their own MathML implementation. If this option is disabled and MathML is not supported, the math
|
||||
* equations are replaced with a warning. If this option is enabled and MathML is not supported, Mermaid will
|
||||
* fall back to legacy rendering for KaTeX.
|
||||
*
|
||||
*/
|
||||
legacyMathML?: boolean;
|
||||
/**
|
||||
* This option controls if the generated ids of nodes in the SVG are
|
||||
* generated randomly or based on a seed.
|
||||
@ -161,10 +169,20 @@ export interface MermaidConfig {
|
||||
gitGraph?: GitGraphDiagramConfig;
|
||||
c4?: C4DiagramConfig;
|
||||
sankey?: SankeyDiagramConfig;
|
||||
block?: BlockDiagramConfig;
|
||||
dompurifyConfig?: DOMPurifyConfiguration;
|
||||
wrap?: boolean;
|
||||
fontSize?: number;
|
||||
}
|
||||
/**
|
||||
* The object containing configurations specific for block diagrams.
|
||||
*
|
||||
* This interface was referenced by `MermaidConfig`'s JSON-Schema
|
||||
* via the `definition` "BlockDiagramConfig".
|
||||
*/
|
||||
export interface BlockDiagramConfig extends BaseDiagramConfig {
|
||||
padding?: number;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `MermaidConfig`'s JSON-Schema
|
||||
* via the `definition` "BaseDiagramConfig".
|
||||
|
@ -24,7 +24,7 @@ flowchart
|
||||
|
||||
The new nodes C1 and C2 are a special type of nodes, clusterNodes. ClusterNodes have have the nodes in the cluster including the cluster attached in a graph object.
|
||||
|
||||
When rendering this diagram it it beeing rendered recursively. The diagram is rendered by the dagre-mermaid:render function which in turn will be used to render the node C1 and the node C2. The result of those renderings will be inserted as nodes in the "root" diagram. With this recursive approach it would be possible to have different layout direction for each cluster.
|
||||
When rendering this diagram it is being rendered recursively. The diagram is rendered by the dagre-mermaid:render function which in turn will be used to render the node C1 and the node C2. The result of those renderings will be inserted as nodes in the "root" diagram. With this recursive approach it would be possible to have different layout direction for each cluster.
|
||||
|
||||
```
|
||||
{ clusterNode: true, graph }
|
||||
|
248
packages/mermaid/src/dagre-wrapper/blockArrowHelper.ts
Normal file
248
packages/mermaid/src/dagre-wrapper/blockArrowHelper.ts
Normal file
@ -0,0 +1,248 @@
|
||||
import type { Direction } from '../../src/diagrams/block/blockTypes.js';
|
||||
|
||||
const expandAndDeduplicateDirections = (directions: Direction[]) => {
|
||||
const uniqueDirections = new Set();
|
||||
|
||||
for (const direction of directions) {
|
||||
switch (direction) {
|
||||
case 'x':
|
||||
uniqueDirections.add('right');
|
||||
uniqueDirections.add('left');
|
||||
break;
|
||||
case 'y':
|
||||
uniqueDirections.add('up');
|
||||
uniqueDirections.add('down');
|
||||
break;
|
||||
default:
|
||||
uniqueDirections.add(direction);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return uniqueDirections;
|
||||
};
|
||||
export const getArrowPoints = (
|
||||
duplicatedDirections: Direction[],
|
||||
bbox: { width: number; height: number },
|
||||
node: any
|
||||
) => {
|
||||
// Expand and deduplicate the provided directions.
|
||||
// for instance: x, right => right, left
|
||||
const directions = expandAndDeduplicateDirections(duplicatedDirections);
|
||||
|
||||
// Factor to divide height for some calculations.
|
||||
const f = 2;
|
||||
|
||||
// Calculated height of the bounding box, accounting for node padding.
|
||||
const height = bbox.height + 2 * node.padding;
|
||||
// Midpoint calculation based on height.
|
||||
const midpoint = height / f;
|
||||
// Calculated width of the bounding box, accounting for additional width and node padding.
|
||||
const width = bbox.width + 2 * midpoint + node.padding;
|
||||
// Padding to use, half of the node padding.
|
||||
const padding = node.padding / 2;
|
||||
|
||||
// Initialize an empty array to store points for the arrow.
|
||||
const points = [];
|
||||
|
||||
if (
|
||||
directions.has('right') &&
|
||||
directions.has('left') &&
|
||||
directions.has('up') &&
|
||||
directions.has('down')
|
||||
) {
|
||||
// SQUARE
|
||||
return [
|
||||
// Bottom
|
||||
{ x: 0, y: 0 },
|
||||
{ x: midpoint, y: 0 },
|
||||
{ x: width / 2, y: 2 * padding },
|
||||
{ x: width - midpoint, y: 0 },
|
||||
{ x: width, y: 0 },
|
||||
|
||||
// Right
|
||||
{ x: width, y: -height / 3 },
|
||||
{ x: width + 2 * padding, y: -height / 2 },
|
||||
{ x: width, y: (-2 * height) / 3 },
|
||||
{ x: width, y: -height },
|
||||
|
||||
// Top
|
||||
{ x: width - midpoint, y: -height },
|
||||
{ x: width / 2, y: -height - 2 * padding },
|
||||
{ x: midpoint, y: -height },
|
||||
|
||||
// Left
|
||||
{ x: 0, y: -height },
|
||||
{ x: 0, y: (-2 * height) / 3 },
|
||||
{ x: -2 * padding, y: -height / 2 },
|
||||
{ x: 0, y: -height / 3 },
|
||||
];
|
||||
}
|
||||
if (directions.has('right') && directions.has('left') && directions.has('up')) {
|
||||
// RECTANGLE_VERTICAL (Top Open)
|
||||
return [
|
||||
{ x: midpoint, y: 0 },
|
||||
{ x: width - midpoint, y: 0 },
|
||||
{ x: width, y: -height / 2 },
|
||||
{ x: width - midpoint, y: -height },
|
||||
{ x: midpoint, y: -height },
|
||||
{ x: 0, y: -height / 2 },
|
||||
];
|
||||
}
|
||||
if (directions.has('right') && directions.has('left') && directions.has('down')) {
|
||||
// RECTANGLE_VERTICAL (Bottom Open)
|
||||
return [
|
||||
{ x: 0, y: 0 },
|
||||
{ x: midpoint, y: -height },
|
||||
{ x: width - midpoint, y: -height },
|
||||
{ x: width, y: 0 },
|
||||
];
|
||||
}
|
||||
if (directions.has('right') && directions.has('up') && directions.has('down')) {
|
||||
// RECTANGLE_HORIZONTAL (Right Open)
|
||||
return [
|
||||
{ x: 0, y: 0 },
|
||||
{ x: width, y: -midpoint },
|
||||
{ x: width, y: -height + midpoint },
|
||||
{ x: 0, y: -height },
|
||||
];
|
||||
}
|
||||
if (directions.has('left') && directions.has('up') && directions.has('down')) {
|
||||
// RECTANGLE_HORIZONTAL (Left Open)
|
||||
return [
|
||||
{ x: width, y: 0 },
|
||||
{ x: 0, y: -midpoint },
|
||||
{ x: 0, y: -height + midpoint },
|
||||
{ x: width, y: -height },
|
||||
];
|
||||
}
|
||||
if (directions.has('right') && directions.has('left')) {
|
||||
// HORIZONTAL_LINE
|
||||
return [
|
||||
{ x: midpoint, y: 0 },
|
||||
{ x: midpoint, y: -padding },
|
||||
{ x: width - midpoint, y: -padding },
|
||||
{ x: width - midpoint, y: 0 },
|
||||
{ x: width, y: -height / 2 },
|
||||
{ x: width - midpoint, y: -height },
|
||||
{ x: width - midpoint, y: -height + padding },
|
||||
{ x: midpoint, y: -height + padding },
|
||||
{ x: midpoint, y: -height },
|
||||
{ x: 0, y: -height / 2 },
|
||||
];
|
||||
}
|
||||
if (directions.has('up') && directions.has('down')) {
|
||||
// VERTICAL_LINE
|
||||
return [
|
||||
// Bottom center
|
||||
{ x: width / 2, y: 0 },
|
||||
// Left pont of bottom arrow
|
||||
{ x: 0, y: -padding },
|
||||
{ x: midpoint, y: -padding },
|
||||
// Left top over vertical section
|
||||
{ x: midpoint, y: -height + padding },
|
||||
{ x: 0, y: -height + padding },
|
||||
// Top of arrow
|
||||
{ x: width / 2, y: -height },
|
||||
{ x: width, y: -height + padding },
|
||||
// Top of right vertical bar
|
||||
{ x: width - midpoint, y: -height + padding },
|
||||
{ x: width - midpoint, y: -padding },
|
||||
{ x: width, y: -padding },
|
||||
];
|
||||
}
|
||||
if (directions.has('right') && directions.has('up')) {
|
||||
// ANGLE_RT
|
||||
return [
|
||||
{ x: 0, y: 0 },
|
||||
{ x: width, y: -midpoint },
|
||||
{ x: 0, y: -height },
|
||||
];
|
||||
}
|
||||
if (directions.has('right') && directions.has('down')) {
|
||||
// ANGLE_RB
|
||||
return [
|
||||
{ x: 0, y: 0 },
|
||||
{ x: width, y: 0 },
|
||||
{ x: 0, y: -height },
|
||||
];
|
||||
}
|
||||
if (directions.has('left') && directions.has('up')) {
|
||||
// ANGLE_LT
|
||||
return [
|
||||
{ x: width, y: 0 },
|
||||
{ x: 0, y: -midpoint },
|
||||
{ x: width, y: -height },
|
||||
];
|
||||
}
|
||||
if (directions.has('left') && directions.has('down')) {
|
||||
// ANGLE_LB
|
||||
return [
|
||||
{ x: width, y: 0 },
|
||||
{ x: 0, y: 0 },
|
||||
{ x: width, y: -height },
|
||||
];
|
||||
}
|
||||
if (directions.has('right')) {
|
||||
// ARROW_RIGHT
|
||||
return [
|
||||
{ x: midpoint, y: -padding },
|
||||
{ x: midpoint, y: -padding },
|
||||
{ x: width - midpoint, y: -padding },
|
||||
{ x: width - midpoint, y: 0 },
|
||||
{ x: width, y: -height / 2 },
|
||||
{ x: width - midpoint, y: -height },
|
||||
{ x: width - midpoint, y: -height + padding },
|
||||
// top left corner of arrow
|
||||
{ x: midpoint, y: -height + padding },
|
||||
{ x: midpoint, y: -height + padding },
|
||||
];
|
||||
}
|
||||
if (directions.has('left')) {
|
||||
// ARROW_LEFT
|
||||
return [
|
||||
{ x: midpoint, y: 0 },
|
||||
{ x: midpoint, y: -padding },
|
||||
// Two points, the right corners
|
||||
{ x: width - midpoint, y: -padding },
|
||||
{ x: width - midpoint, y: -height + padding },
|
||||
{ x: midpoint, y: -height + padding },
|
||||
{ x: midpoint, y: -height },
|
||||
{ x: 0, y: -height / 2 },
|
||||
];
|
||||
}
|
||||
if (directions.has('up')) {
|
||||
// ARROW_TOP
|
||||
return [
|
||||
// Bottom center
|
||||
{ x: midpoint, y: -padding },
|
||||
// Left top over vertical section
|
||||
{ x: midpoint, y: -height + padding },
|
||||
{ x: 0, y: -height + padding },
|
||||
// Top of arrow
|
||||
{ x: width / 2, y: -height },
|
||||
{ x: width, y: -height + padding },
|
||||
// Top of right vertical bar
|
||||
{ x: width - midpoint, y: -height + padding },
|
||||
{ x: width - midpoint, y: -padding },
|
||||
];
|
||||
}
|
||||
if (directions.has('down')) {
|
||||
// ARROW_BOTTOM
|
||||
return [
|
||||
// Bottom center
|
||||
{ x: width / 2, y: 0 },
|
||||
// Left pont of bottom arrow
|
||||
{ x: 0, y: -padding },
|
||||
{ x: midpoint, y: -padding },
|
||||
// Left top over vertical section
|
||||
{ x: midpoint, y: -height + padding },
|
||||
{ x: width - midpoint, y: -height + padding },
|
||||
{ x: width - midpoint, y: -padding },
|
||||
{ x: width, y: -padding },
|
||||
];
|
||||
}
|
||||
|
||||
// POINT
|
||||
return [{ x: 0, y: 0 }];
|
||||
};
|
@ -69,13 +69,13 @@ const rect = (parent, node) => {
|
||||
if (useHtmlLabels) {
|
||||
label.attr(
|
||||
'transform',
|
||||
// This puts the labal on top of the box instead of inside it
|
||||
// This puts the label on top of the box instead of inside it
|
||||
`translate(${node.x - bbox.width / 2}, ${node.y - node.height / 2 + subGraphTitleTopMargin})`
|
||||
);
|
||||
} else {
|
||||
label.attr(
|
||||
'transform',
|
||||
// This puts the labal on top of the box instead of inside it
|
||||
// This puts the label on top of the box instead of inside it
|
||||
`translate(${node.x}, ${node.y - node.height / 2 + subGraphTitleTopMargin})`
|
||||
);
|
||||
}
|
||||
|
@ -56,11 +56,11 @@ const createLabel = (_vertexText, style, isTitle, isNode) => {
|
||||
if (evaluate(getConfig().flowchart.htmlLabels)) {
|
||||
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
|
||||
vertexText = vertexText.replace(/\\n|\n/g, '<br />');
|
||||
log.info('vertexText' + vertexText);
|
||||
log.debug('vertexText' + vertexText);
|
||||
const node = {
|
||||
isNode,
|
||||
label: decodeEntities(vertexText).replace(
|
||||
/fa[blrs]?:fa-[\w-]+/g,
|
||||
/fa[blrs]?:fa-[\w-]+/g, // cspell: disable-line
|
||||
(s) => `<i class='${s.replace(':', ' ')}'></i>`
|
||||
),
|
||||
labelStyle: style.replace('fill:', 'color:'),
|
||||
|
@ -28,7 +28,6 @@ export const insertEdgeLabel = (elem, edge) => {
|
||||
addSvgBackground: true,
|
||||
})
|
||||
: createLabel(edge.label, edge.labelStyle);
|
||||
log.info('abc82', edge, edge.labelType);
|
||||
|
||||
// Create outer g, edgeLabel, this will be positioned after graph layout
|
||||
const edgeLabel = elem.insert('g').attr('class', 'edgeLabel');
|
||||
@ -135,7 +134,7 @@ function setTerminalWidth(fo, value) {
|
||||
}
|
||||
|
||||
export const positionEdgeLabel = (edge, paths) => {
|
||||
log.info('Moving label abc78 ', edge.id, edge.label, edgeLabels[edge.id]);
|
||||
log.debug('Moving label abc88 ', edge.id, edge.label, edgeLabels[edge.id], paths);
|
||||
let path = paths.updatedPath ? paths.updatedPath : paths.originalPath;
|
||||
const siteConfig = getConfig();
|
||||
const { subGraphTitleTotalMargin } = getSubGraphTitleMargins(siteConfig);
|
||||
@ -146,7 +145,7 @@ export const positionEdgeLabel = (edge, paths) => {
|
||||
if (path) {
|
||||
// // debugger;
|
||||
const pos = utils.calcLabelPosition(path);
|
||||
log.info(
|
||||
log.debug(
|
||||
'Moving label ' + edge.label + ' from (',
|
||||
x,
|
||||
',',
|
||||
@ -155,7 +154,7 @@ export const positionEdgeLabel = (edge, paths) => {
|
||||
pos.x,
|
||||
',',
|
||||
pos.y,
|
||||
') abc78'
|
||||
') abc88'
|
||||
);
|
||||
if (paths.updatedPath) {
|
||||
x = pos.x;
|
||||
@ -221,7 +220,6 @@ export const positionEdgeLabel = (edge, paths) => {
|
||||
};
|
||||
|
||||
const outsideNode = (node, point) => {
|
||||
// log.warn('Checking bounds ', node, point);
|
||||
const x = node.x;
|
||||
const y = node.y;
|
||||
const dx = Math.abs(point.x - x);
|
||||
@ -235,7 +233,7 @@ const outsideNode = (node, point) => {
|
||||
};
|
||||
|
||||
export const intersection = (node, outsidePoint, insidePoint) => {
|
||||
log.warn(`intersection calc abc89:
|
||||
log.debug(`intersection calc abc89:
|
||||
outsidePoint: ${JSON.stringify(outsidePoint)}
|
||||
insidePoint : ${JSON.stringify(insidePoint)}
|
||||
node : x:${node.x} y:${node.y} w:${node.width} h:${node.height}`);
|
||||
@ -248,29 +246,11 @@ export const intersection = (node, outsidePoint, insidePoint) => {
|
||||
let r = insidePoint.x < outsidePoint.x ? w - dx : w + dx;
|
||||
const h = node.height / 2;
|
||||
|
||||
// const edges = {
|
||||
// x1: x - w,
|
||||
// x2: x + w,
|
||||
// y1: y - h,
|
||||
// y2: y + h
|
||||
// };
|
||||
|
||||
// if (
|
||||
// outsidePoint.x === edges.x1 ||
|
||||
// outsidePoint.x === edges.x2 ||
|
||||
// outsidePoint.y === edges.y1 ||
|
||||
// outsidePoint.y === edges.y2
|
||||
// ) {
|
||||
// log.warn('abc89 calc equals on edge', outsidePoint, edges);
|
||||
// return outsidePoint;
|
||||
// }
|
||||
|
||||
const Q = Math.abs(outsidePoint.y - insidePoint.y);
|
||||
const R = Math.abs(outsidePoint.x - insidePoint.x);
|
||||
// log.warn();
|
||||
|
||||
if (Math.abs(y - outsidePoint.y) * w > Math.abs(x - outsidePoint.x) * h) {
|
||||
// Intersection is top or bottom of rect.
|
||||
// let q = insidePoint.y < outsidePoint.y ? outsidePoint.y - h - y : y - h - outsidePoint.y;
|
||||
let q = insidePoint.y < outsidePoint.y ? outsidePoint.y - h - y : y - h - outsidePoint.y;
|
||||
r = (R * q) / Q;
|
||||
const res = {
|
||||
@ -289,7 +269,7 @@ export const intersection = (node, outsidePoint, insidePoint) => {
|
||||
res.y = outsidePoint.y;
|
||||
}
|
||||
|
||||
log.warn(`abc89 topp/bott calc, Q ${Q}, q ${q}, R ${R}, r ${r}`, res);
|
||||
log.debug(`abc89 topp/bott calc, Q ${Q}, q ${q}, R ${R}, r ${r}`, res); // cspell: disable-line
|
||||
|
||||
return res;
|
||||
} else {
|
||||
@ -306,7 +286,7 @@ export const intersection = (node, outsidePoint, insidePoint) => {
|
||||
let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : insidePoint.x - R + r;
|
||||
// let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : outsidePoint.x + r;
|
||||
let _y = insidePoint.y < outsidePoint.y ? insidePoint.y + q : insidePoint.y - q;
|
||||
log.warn(`sides calc abc89, Q ${Q}, q ${q}, R ${R}, r ${r}`, { _x, _y });
|
||||
log.debug(`sides calc abc89, Q ${Q}, q ${q}, R ${R}, r ${r}`, { _x, _y });
|
||||
if (r === 0) {
|
||||
_x = outsidePoint.x;
|
||||
_y = outsidePoint.y;
|
||||
@ -326,25 +306,20 @@ export const intersection = (node, outsidePoint, insidePoint) => {
|
||||
* and return an update path ending by the border of the node.
|
||||
*
|
||||
* @param {Array} _points
|
||||
* @param {any} boundryNode
|
||||
* @param {any} boundaryNode
|
||||
* @returns {Array} Points
|
||||
*/
|
||||
const cutPathAtIntersect = (_points, boundryNode) => {
|
||||
log.warn('abc88 cutPathAtIntersect', _points, boundryNode);
|
||||
const cutPathAtIntersect = (_points, boundaryNode) => {
|
||||
log.debug('abc88 cutPathAtIntersect', _points, boundaryNode);
|
||||
let points = [];
|
||||
let lastPointOutside = _points[0];
|
||||
let isInside = false;
|
||||
_points.forEach((point) => {
|
||||
// const node = clusterDb[edge.toCluster].node;
|
||||
log.info('abc88 checking point', point, boundryNode);
|
||||
|
||||
// check if point is inside the boundary rect
|
||||
if (!outsideNode(boundryNode, point) && !isInside) {
|
||||
if (!outsideNode(boundaryNode, point) && !isInside) {
|
||||
// First point inside the rect found
|
||||
// Calc the intersection coord between the point anf the last point outside the rect
|
||||
const inter = intersection(boundryNode, lastPointOutside, point);
|
||||
log.warn('abc88 inside', point, lastPointOutside, inter);
|
||||
log.warn('abc88 intersection', inter);
|
||||
const inter = intersection(boundaryNode, lastPointOutside, point);
|
||||
|
||||
// // Check case where the intersection is the same as the last point
|
||||
let pointPresent = false;
|
||||
@ -354,14 +329,11 @@ const cutPathAtIntersect = (_points, boundryNode) => {
|
||||
// // if (!pointPresent) {
|
||||
if (!points.some((e) => e.x === inter.x && e.y === inter.y)) {
|
||||
points.push(inter);
|
||||
} else {
|
||||
log.warn('abc88 no intersect', inter, points);
|
||||
}
|
||||
// points.push(inter);
|
||||
|
||||
isInside = true;
|
||||
} else {
|
||||
// Outside
|
||||
log.warn('abc88 outside', point, lastPointOutside);
|
||||
lastPointOutside = point;
|
||||
// points.push(point);
|
||||
if (!isInside) {
|
||||
@ -369,67 +341,31 @@ const cutPathAtIntersect = (_points, boundryNode) => {
|
||||
}
|
||||
}
|
||||
});
|
||||
log.warn('abc88 returning points', points);
|
||||
return points;
|
||||
};
|
||||
|
||||
export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph, id) {
|
||||
let points = edge.points;
|
||||
log.debug('abc88 InsertEdge: edge=', edge, 'e=', e);
|
||||
let pointsHasChanged = false;
|
||||
const tail = graph.node(e.v);
|
||||
var head = graph.node(e.w);
|
||||
|
||||
log.info('abc88 InsertEdge: ', edge);
|
||||
if (head.intersect && tail.intersect) {
|
||||
if (head?.intersect && tail?.intersect) {
|
||||
points = points.slice(1, edge.points.length - 1);
|
||||
points.unshift(tail.intersect(points[0]));
|
||||
log.info(
|
||||
'Last point',
|
||||
points[points.length - 1],
|
||||
head,
|
||||
head.intersect(points[points.length - 1])
|
||||
);
|
||||
points.push(head.intersect(points[points.length - 1]));
|
||||
}
|
||||
|
||||
if (edge.toCluster) {
|
||||
log.info('to cluster abc88', clusterDb[edge.toCluster]);
|
||||
log.debug('to cluster abc88', clusterDb[edge.toCluster]);
|
||||
points = cutPathAtIntersect(edge.points, clusterDb[edge.toCluster].node);
|
||||
// log.trace('edge', edge);
|
||||
// points = [];
|
||||
// let lastPointOutside; // = edge.points[0];
|
||||
// let isInside = false;
|
||||
// edge.points.forEach(point => {
|
||||
// const node = clusterDb[edge.toCluster].node;
|
||||
// log.warn('checking from', edge.fromCluster, point, node);
|
||||
|
||||
// if (!outsideNode(node, point) && !isInside) {
|
||||
// log.trace('inside', edge.toCluster, point, lastPointOutside);
|
||||
|
||||
// // First point inside the rect
|
||||
// const inter = intersection(node, lastPointOutside, point);
|
||||
|
||||
// let pointPresent = false;
|
||||
// points.forEach(p => {
|
||||
// pointPresent = pointPresent || (p.x === inter.x && p.y === inter.y);
|
||||
// });
|
||||
// // if (!pointPresent) {
|
||||
// if (!points.find(e => e.x === inter.x && e.y === inter.y)) {
|
||||
// points.push(inter);
|
||||
// } else {
|
||||
// log.warn('no intersect', inter, points);
|
||||
// }
|
||||
// isInside = true;
|
||||
// } else {
|
||||
// // outside
|
||||
// lastPointOutside = point;
|
||||
// if (!isInside) points.push(point);
|
||||
// }
|
||||
// });
|
||||
pointsHasChanged = true;
|
||||
}
|
||||
|
||||
if (edge.fromCluster) {
|
||||
log.info('from cluster abc88', clusterDb[edge.fromCluster]);
|
||||
log.debug('from cluster abc88', clusterDb[edge.fromCluster]);
|
||||
points = cutPathAtIntersect(points.reverse(), clusterDb[edge.fromCluster].node).reverse();
|
||||
|
||||
pointsHasChanged = true;
|
||||
@ -507,8 +443,6 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph
|
||||
url = url.replace(/\(/g, '\\(');
|
||||
url = url.replace(/\)/g, '\\)');
|
||||
}
|
||||
log.info('arrowTypeStart', edge.arrowTypeStart);
|
||||
log.info('arrowTypeEnd', edge.arrowTypeEnd);
|
||||
|
||||
addEdgeMarkers(svgPath, edge, url, id, diagramType);
|
||||
|
||||
|
@ -16,7 +16,7 @@ import { log } from '../logger.js';
|
||||
import { getSubGraphTitleMargins } from '../utils/subGraphTitleMargins.js';
|
||||
import { getConfig } from '../diagram-api/diagramAPI.js';
|
||||
|
||||
const recursiveRender = async (_elem, graph, diagramtype, id, parentCluster, siteConfig) => {
|
||||
const recursiveRender = async (_elem, graph, diagramType, id, parentCluster, siteConfig) => {
|
||||
log.info('Graph in recursive render: XXX', graphlibJson.write(graph), parentCluster);
|
||||
const dir = graph.graph().rankdir;
|
||||
log.trace('Dir in recursive render - dir:', dir);
|
||||
@ -65,7 +65,7 @@ const recursiveRender = async (_elem, graph, diagramtype, id, parentCluster, sit
|
||||
const o = await recursiveRender(
|
||||
nodes,
|
||||
node.graph,
|
||||
diagramtype,
|
||||
diagramType,
|
||||
id,
|
||||
graph.node(v),
|
||||
siteConfig
|
||||
@ -103,7 +103,7 @@ const recursiveRender = async (_elem, graph, diagramtype, id, parentCluster, sit
|
||||
log.info('Edge ' + e.v + ' -> ' + e.w + ': ', e, ' ', JSON.stringify(graph.edge(e)));
|
||||
|
||||
// Check if link is either from or to a cluster
|
||||
log.info('Fix', clusterDb, 'ids:', e.v, e.w, 'Translateing: ', clusterDb[e.v], clusterDb[e.w]);
|
||||
log.info('Fix', clusterDb, 'ids:', e.v, e.w, 'Translating: ', clusterDb[e.v], clusterDb[e.w]);
|
||||
insertEdgeLabel(edgeLabels, edge);
|
||||
});
|
||||
|
||||
@ -155,7 +155,7 @@ const recursiveRender = async (_elem, graph, diagramtype, id, parentCluster, sit
|
||||
log.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(edge), edge);
|
||||
|
||||
edge.points.forEach((point) => (point.y += subGraphTitleTotalMargin / 2));
|
||||
const paths = insertEdge(edgePaths, e, edge, clusterDb, diagramtype, graph, id);
|
||||
const paths = insertEdge(edgePaths, e, edge, clusterDb, diagramType, graph, id);
|
||||
positionEdgeLabel(edge, paths);
|
||||
});
|
||||
|
||||
@ -169,8 +169,8 @@ const recursiveRender = async (_elem, graph, diagramtype, id, parentCluster, sit
|
||||
return { elem, diff };
|
||||
};
|
||||
|
||||
export const render = async (elem, graph, markers, diagramtype, id) => {
|
||||
insertMarkers(elem, markers, diagramtype, id);
|
||||
export const render = async (elem, graph, markers, diagramType, id) => {
|
||||
insertMarkers(elem, markers, diagramType, id);
|
||||
clearNodes();
|
||||
clearEdges();
|
||||
clearClusters();
|
||||
@ -181,7 +181,7 @@ export const render = async (elem, graph, markers, diagramtype, id) => {
|
||||
log.warn('Graph after:', JSON.stringify(graphlibJson.write(graph)));
|
||||
// log.warn('Graph ever after:', graphlibJson.write(graph.node('A').graph));
|
||||
const siteConfig = getConfig();
|
||||
await recursiveRender(elem, graph, diagramtype, id, undefined, siteConfig);
|
||||
await recursiveRender(elem, graph, diagramType, id, undefined, siteConfig);
|
||||
};
|
||||
|
||||
// const shapeDefinitions = {};
|
||||
|
@ -13,11 +13,11 @@ export const clear = () => {
|
||||
clusterDb = {};
|
||||
};
|
||||
|
||||
const isDescendant = (id, ancenstorId) => {
|
||||
// if (id === ancenstorId) return true;
|
||||
const isDescendant = (id, ancestorId) => {
|
||||
// if (id === ancestorId) return true;
|
||||
|
||||
log.trace('In isDecendant', ancenstorId, ' ', id, ' = ', descendants[ancenstorId].includes(id));
|
||||
if (descendants[ancenstorId].includes(id)) {
|
||||
log.trace('In isDescendant', ancestorId, ' ', id, ' = ', descendants[ancestorId].includes(id));
|
||||
if (descendants[ancestorId].includes(id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ const isDescendant = (id, ancenstorId) => {
|
||||
};
|
||||
|
||||
const edgeInCluster = (edge, clusterId) => {
|
||||
log.info('Decendants of ', clusterId, ' is ', descendants[clusterId]);
|
||||
log.info('Descendants of ', clusterId, ' is ', descendants[clusterId]);
|
||||
log.info('Edge is ', edge);
|
||||
// Edges to/from the cluster is not in the cluster, they are in the parent
|
||||
if (edge.v === clusterId) {
|
||||
@ -36,7 +36,7 @@ const edgeInCluster = (edge, clusterId) => {
|
||||
}
|
||||
|
||||
if (!descendants[clusterId]) {
|
||||
log.debug('Tilt, ', clusterId, ',not in decendants');
|
||||
log.debug('Tilt, ', clusterId, ',not in descendants');
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
@ -244,7 +244,7 @@ export const adjustClustersAndEdges = (graph, depth) => {
|
||||
// d1 xor d2 - if either d1 is true and d2 is false or the other way around
|
||||
if (d1 ^ d2) {
|
||||
log.warn('Edge: ', edge, ' leaves cluster ', id);
|
||||
log.warn('Decendants of XXX ', id, ': ', descendants[id]);
|
||||
log.warn('Descendants of XXX ', id, ': ', descendants[id]);
|
||||
clusterDb[id].externalConnections = true;
|
||||
}
|
||||
}
|
||||
@ -286,6 +286,7 @@ export const adjustClustersAndEdges = (graph, depth) => {
|
||||
clusterDb[e.w]
|
||||
);
|
||||
if (clusterDb[e.v] && clusterDb[e.w] && clusterDb[e.v] === clusterDb[e.w]) {
|
||||
// cspell:ignore trixing
|
||||
log.warn('Fixing and trixing link to self - removing XXX', e.v, e.w, e.name);
|
||||
log.warn('Fixing and trixing - removing XXX', e.v, e.w, e.name);
|
||||
v = getAnchorId(e.v);
|
||||
@ -337,7 +338,7 @@ export const adjustClustersAndEdges = (graph, depth) => {
|
||||
|
||||
// Remove references to extracted cluster
|
||||
// graph.edges().forEach(edge => {
|
||||
// if (isDecendant(edge.v, clusterId) || isDecendant(edge.w, clusterId)) {
|
||||
// if (isDescendant(edge.v, clusterId) || isDescendant(edge.w, clusterId)) {
|
||||
// graph.removeEdge(edge);
|
||||
// }
|
||||
// });
|
||||
|
@ -6,6 +6,7 @@ import intersect from './intersect/index.js';
|
||||
import createLabel from './createLabel.js';
|
||||
import note from './shapes/note.js';
|
||||
import { evaluate } from '../diagrams/common/common.js';
|
||||
import { getArrowPoints } from './blockArrowHelper.js';
|
||||
|
||||
const formatClass = (str) => {
|
||||
if (str) {
|
||||
@ -30,6 +31,7 @@ const question = async (parent, node) => {
|
||||
const w = bbox.width + node.padding;
|
||||
const h = bbox.height + node.padding;
|
||||
const s = w + h;
|
||||
|
||||
const points = [
|
||||
{ x: s / 2, y: 0 },
|
||||
{ x: s, y: -s / 2 },
|
||||
@ -117,6 +119,27 @@ const hexagon = async (parent, node) => {
|
||||
return shapeSvg;
|
||||
};
|
||||
|
||||
const block_arrow = async (parent, node) => {
|
||||
const { shapeSvg, bbox } = await labelHelper(parent, node, undefined, true);
|
||||
|
||||
const f = 2;
|
||||
const h = bbox.height + 2 * node.padding;
|
||||
const m = h / f;
|
||||
const w = bbox.width + 2 * m + node.padding;
|
||||
|
||||
const points = getArrowPoints(node.directions, bbox, node);
|
||||
|
||||
const blockArrow = insertPolygonShape(shapeSvg, w, h, points);
|
||||
blockArrow.attr('style', node.style);
|
||||
updateNodeBounds(node, blockArrow);
|
||||
|
||||
node.intersect = function (point) {
|
||||
return intersect.polygon(node, points, point);
|
||||
};
|
||||
|
||||
return shapeSvg;
|
||||
};
|
||||
|
||||
const rect_left_inv_arrow = async (parent, node) => {
|
||||
const { shapeSvg, bbox } = await labelHelper(
|
||||
parent,
|
||||
@ -374,17 +397,64 @@ const rect = async (parent, node) => {
|
||||
|
||||
// const totalWidth = bbox.width + node.padding * 2;
|
||||
// const totalHeight = bbox.height + node.padding * 2;
|
||||
const totalWidth = bbox.width + node.padding;
|
||||
const totalHeight = bbox.height + node.padding;
|
||||
const totalWidth = node.positioned ? node.width : bbox.width + node.padding;
|
||||
const totalHeight = node.positioned ? node.height : bbox.height + node.padding;
|
||||
const x = node.positioned ? -totalWidth / 2 : -bbox.width / 2 - halfPadding;
|
||||
const y = node.positioned ? -totalHeight / 2 : -bbox.height / 2 - halfPadding;
|
||||
rect
|
||||
.attr('class', 'basic label-container')
|
||||
.attr('style', node.style)
|
||||
.attr('rx', node.rx)
|
||||
.attr('ry', node.ry)
|
||||
// .attr('x', -bbox.width / 2 - node.padding)
|
||||
// .attr('y', -bbox.height / 2 - node.padding)
|
||||
.attr('x', -bbox.width / 2 - halfPadding)
|
||||
.attr('y', -bbox.height / 2 - halfPadding)
|
||||
.attr('x', x)
|
||||
.attr('y', y)
|
||||
.attr('width', totalWidth)
|
||||
.attr('height', totalHeight);
|
||||
|
||||
if (node.props) {
|
||||
const propKeys = new Set(Object.keys(node.props));
|
||||
if (node.props.borders) {
|
||||
applyNodePropertyBorders(rect, node.props.borders, totalWidth, totalHeight);
|
||||
propKeys.delete('borders');
|
||||
}
|
||||
propKeys.forEach((propKey) => {
|
||||
log.warn(`Unknown node property ${propKey}`);
|
||||
});
|
||||
}
|
||||
|
||||
updateNodeBounds(node, rect);
|
||||
|
||||
node.intersect = function (point) {
|
||||
return intersect.rect(node, point);
|
||||
};
|
||||
|
||||
return shapeSvg;
|
||||
};
|
||||
|
||||
const composite = async (parent, node) => {
|
||||
const { shapeSvg, bbox, halfPadding } = await labelHelper(
|
||||
parent,
|
||||
node,
|
||||
'node ' + node.classes,
|
||||
true
|
||||
);
|
||||
|
||||
// add the rect
|
||||
const rect = shapeSvg.insert('rect', ':first-child');
|
||||
|
||||
// const totalWidth = bbox.width + node.padding * 2;
|
||||
// const totalHeight = bbox.height + node.padding * 2;
|
||||
const totalWidth = node.positioned ? node.width : bbox.width + node.padding;
|
||||
const totalHeight = node.positioned ? node.height : bbox.height + node.padding;
|
||||
const x = node.positioned ? -totalWidth / 2 : -bbox.width / 2 - halfPadding;
|
||||
const y = node.positioned ? -totalHeight / 2 : -bbox.height / 2 - halfPadding;
|
||||
rect
|
||||
.attr('class', 'basic cluster composite label-container')
|
||||
.attr('style', node.style)
|
||||
.attr('rx', node.rx)
|
||||
.attr('ry', node.ry)
|
||||
.attr('x', x)
|
||||
.attr('y', y)
|
||||
.attr('width', totalWidth)
|
||||
.attr('height', totalHeight);
|
||||
|
||||
@ -1031,6 +1101,7 @@ const class_box = (parent, node) => {
|
||||
|
||||
const shapes = {
|
||||
rhombus: question,
|
||||
composite,
|
||||
question,
|
||||
rect,
|
||||
labelRect,
|
||||
@ -1040,6 +1111,7 @@ const shapes = {
|
||||
doublecircle,
|
||||
stadium,
|
||||
hexagon,
|
||||
block_arrow,
|
||||
rect_left_inv_arrow,
|
||||
lean_right,
|
||||
lean_left,
|
||||
@ -1082,6 +1154,9 @@ export const insertNode = async (elem, node, dir) => {
|
||||
if (node.class) {
|
||||
el.attr('class', 'node default ' + node.class);
|
||||
}
|
||||
// MC Special
|
||||
newEl.attr('data-node', 'true');
|
||||
newEl.attr('data-id', node.id);
|
||||
|
||||
nodeElems[node.id] = newEl;
|
||||
|
||||
@ -1099,7 +1174,6 @@ export const clear = () => {
|
||||
|
||||
export const positionNode = (node) => {
|
||||
const el = nodeElems[node.id];
|
||||
|
||||
log.trace(
|
||||
'Transforming node',
|
||||
node.diff,
|
||||
|
@ -115,6 +115,7 @@ export const labelHelper = async (parent, node, _classes, isNode) => {
|
||||
label.attr('transform', 'translate(' + -bbox.width / 2 + ', ' + -bbox.height / 2 + ')');
|
||||
}
|
||||
label.insert('rect', ':first-child');
|
||||
|
||||
return { shapeSvg, bbox, halfPadding, label };
|
||||
};
|
||||
|
||||
|
@ -20,6 +20,7 @@ import flowchartElk from '../diagrams/flowchart/elk/detector.js';
|
||||
import timeline from '../diagrams/timeline/detector.js';
|
||||
import mindmap from '../diagrams/mindmap/detector.js';
|
||||
import sankey from '../diagrams/sankey/sankeyDetector.js';
|
||||
import block from '../diagrams/block/blockDetector.js';
|
||||
import { registerLazyLoadedDiagrams } from './detectType.js';
|
||||
import { registerDiagram } from './diagramAPI.js';
|
||||
|
||||
@ -87,6 +88,7 @@ export const addDiagrams = () => {
|
||||
journey,
|
||||
quadrantChart,
|
||||
sankey,
|
||||
xychart
|
||||
xychart,
|
||||
block
|
||||
);
|
||||
};
|
||||
|
@ -32,7 +32,7 @@ export interface DiagramDB {
|
||||
getDiagramTitle?: () => string;
|
||||
setAccTitle?: (title: string) => void;
|
||||
getAccTitle?: () => string;
|
||||
setAccDescription?: (describetion: string) => void;
|
||||
setAccDescription?: (description: string) => void;
|
||||
getAccDescription?: () => string;
|
||||
|
||||
setDisplayMode?: (title: string) => void;
|
||||
|
311
packages/mermaid/src/diagrams/block/blockDB.ts
Normal file
311
packages/mermaid/src/diagrams/block/blockDB.ts
Normal file
@ -0,0 +1,311 @@
|
||||
import type { DiagramDB } from '../../diagram-api/types.js';
|
||||
import type { BlockConfig, BlockType, Block, ClassDef } from './blockTypes.js';
|
||||
import * as configApi from '../../config.js';
|
||||
import { clear as commonClear } from '../common/commonDb.js';
|
||||
import { log } from '../../logger.js';
|
||||
import clone from 'lodash-es/clone.js';
|
||||
|
||||
// Initialize the node database for simple lookups
|
||||
let blockDatabase: Record<string, Block> = {};
|
||||
let edgeList: Block[] = [];
|
||||
let edgeCount: Record<string, number> = {};
|
||||
|
||||
const COLOR_KEYWORD = 'color';
|
||||
const FILL_KEYWORD = 'fill';
|
||||
const BG_FILL = 'bgFill';
|
||||
const STYLECLASS_SEP = ',';
|
||||
|
||||
let classes = {} as Record<string, ClassDef>;
|
||||
|
||||
/**
|
||||
* Called when the parser comes across a (style) class definition
|
||||
* @example classDef my-style fill:#f96;
|
||||
*
|
||||
* @param id - the id of this (style) class
|
||||
* @param styleAttributes - the string with 1 or more style attributes (each separated by a comma)
|
||||
*/
|
||||
export const addStyleClass = function (id: string, styleAttributes = '') {
|
||||
// create a new style class object with this id
|
||||
if (classes[id] === undefined) {
|
||||
classes[id] = { id: id, styles: [], textStyles: [] }; // This is a classDef
|
||||
}
|
||||
const foundClass = classes[id];
|
||||
if (styleAttributes !== undefined && styleAttributes !== null) {
|
||||
styleAttributes.split(STYLECLASS_SEP).forEach((attrib) => {
|
||||
// remove any trailing ;
|
||||
const fixedAttrib = attrib.replace(/([^;]*);/, '$1').trim();
|
||||
|
||||
// replace some style keywords
|
||||
if (attrib.match(COLOR_KEYWORD)) {
|
||||
const newStyle1 = fixedAttrib.replace(FILL_KEYWORD, BG_FILL);
|
||||
const newStyle2 = newStyle1.replace(COLOR_KEYWORD, FILL_KEYWORD);
|
||||
foundClass.textStyles.push(newStyle2);
|
||||
}
|
||||
foundClass.styles.push(fixedAttrib);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when the parser comes across a style definition
|
||||
* @example style my-block-id fill:#f96;
|
||||
*
|
||||
* @param id - the id of the block to style
|
||||
* @param styles - the string with 1 or more style attributes (each separated by a comma)
|
||||
*/
|
||||
export const addStyle2Node = function (id: string, styles = '') {
|
||||
const foundBlock = blockDatabase[id];
|
||||
if (styles !== undefined && styles !== null) {
|
||||
foundBlock.styles = styles.split(STYLECLASS_SEP);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a CSS/style class to the block with the given id.
|
||||
* If the block isn't already in the list of known blocks, add it.
|
||||
* Might be called by parser when a CSS/style class should be applied to a block
|
||||
*
|
||||
* @param itemIds - The id or a list of ids of the item(s) to apply the css class to
|
||||
* @param cssClassName - CSS class name
|
||||
*/
|
||||
export const setCssClass = function (itemIds: string, cssClassName: string) {
|
||||
itemIds.split(',').forEach(function (id: string) {
|
||||
let foundBlock = blockDatabase[id];
|
||||
if (foundBlock === undefined) {
|
||||
const trimmedId = id.trim();
|
||||
blockDatabase[trimmedId] = { id: trimmedId, type: 'na', children: [] } as Block;
|
||||
foundBlock = blockDatabase[trimmedId];
|
||||
}
|
||||
if (!foundBlock.classes) {
|
||||
foundBlock.classes = [];
|
||||
}
|
||||
foundBlock.classes.push(cssClassName);
|
||||
});
|
||||
};
|
||||
|
||||
const populateBlockDatabase = (_blockList: Block[] | Block[][], parent: Block): void => {
|
||||
const blockList = _blockList.flat();
|
||||
const children = [];
|
||||
for (const block of blockList) {
|
||||
if (block.type === 'classDef') {
|
||||
addStyleClass(block.id, block.css);
|
||||
continue;
|
||||
}
|
||||
if (block.type === 'applyClass') {
|
||||
setCssClass(block.id, block?.styleClass || '');
|
||||
continue;
|
||||
}
|
||||
if (block.type === 'applyStyles') {
|
||||
if (block?.stylesStr) {
|
||||
addStyle2Node(block.id, block?.stylesStr);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (block.type === 'column-setting') {
|
||||
parent.columns = block.columns || -1;
|
||||
} else if (block.type === 'edge') {
|
||||
if (edgeCount[block.id]) {
|
||||
edgeCount[block.id]++;
|
||||
} else {
|
||||
edgeCount[block.id] = 1;
|
||||
}
|
||||
block.id = edgeCount[block.id] + '-' + block.id;
|
||||
edgeList.push(block);
|
||||
} else {
|
||||
if (!block.label) {
|
||||
if (block.type === 'composite') {
|
||||
block.label = '';
|
||||
// log.debug('abc89 composite', block);
|
||||
} else {
|
||||
block.label = block.id;
|
||||
}
|
||||
}
|
||||
const newBlock = !blockDatabase[block.id];
|
||||
if (newBlock) {
|
||||
blockDatabase[block.id] = block;
|
||||
} else {
|
||||
// Add newer relevant data to aggregated node
|
||||
if (block.type !== 'na') {
|
||||
blockDatabase[block.id].type = block.type;
|
||||
}
|
||||
if (block.label !== block.id) {
|
||||
blockDatabase[block.id].label = block.label;
|
||||
}
|
||||
}
|
||||
|
||||
if (block.children) {
|
||||
populateBlockDatabase(block.children, block);
|
||||
}
|
||||
if (block.type === 'space') {
|
||||
// log.debug('abc95 space', block);
|
||||
const w = block.width || 1;
|
||||
for (let j = 0; j < w; j++) {
|
||||
const newBlock = clone(block);
|
||||
newBlock.id = newBlock.id + '-' + j;
|
||||
blockDatabase[newBlock.id] = newBlock;
|
||||
children.push(newBlock);
|
||||
}
|
||||
} else if (newBlock) {
|
||||
children.push(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
parent.children = children;
|
||||
};
|
||||
|
||||
let blocks: Block[] = [];
|
||||
let rootBlock = { id: 'root', type: 'composite', children: [], columns: -1 } as Block;
|
||||
|
||||
const clear = (): void => {
|
||||
log.debug('Clear called');
|
||||
commonClear();
|
||||
rootBlock = { id: 'root', type: 'composite', children: [], columns: -1 } as Block;
|
||||
blockDatabase = { root: rootBlock };
|
||||
blocks = [] as Block[];
|
||||
classes = {} as Record<string, ClassDef>;
|
||||
|
||||
edgeList = [];
|
||||
edgeCount = {};
|
||||
};
|
||||
|
||||
export function typeStr2Type(typeStr: string) {
|
||||
log.debug('typeStr2Type', typeStr);
|
||||
switch (typeStr) {
|
||||
case '[]':
|
||||
return 'square';
|
||||
case '()':
|
||||
log.debug('we have a round');
|
||||
return 'round';
|
||||
case '(())':
|
||||
return 'circle';
|
||||
case '>]':
|
||||
return 'rect_left_inv_arrow';
|
||||
case '{}':
|
||||
return 'diamond';
|
||||
case '{{}}':
|
||||
return 'hexagon';
|
||||
case '([])':
|
||||
return 'stadium';
|
||||
case '[[]]':
|
||||
return 'subroutine';
|
||||
case '[()]':
|
||||
return 'cylinder';
|
||||
case '((()))':
|
||||
return 'doublecircle';
|
||||
case '[//]':
|
||||
return 'lean_right';
|
||||
case '[\\\\]':
|
||||
return 'lean_left';
|
||||
case '[/\\]':
|
||||
return 'trapezoid';
|
||||
case '[\\/]':
|
||||
return 'inv_trapezoid';
|
||||
case '<[]>':
|
||||
return 'block_arrow';
|
||||
default:
|
||||
return 'na';
|
||||
}
|
||||
}
|
||||
|
||||
export function edgeTypeStr2Type(typeStr: string): string {
|
||||
log.debug('typeStr2Type', typeStr);
|
||||
switch (typeStr) {
|
||||
case '==':
|
||||
return 'thick';
|
||||
default:
|
||||
return 'normal';
|
||||
}
|
||||
}
|
||||
|
||||
export function edgeStrToEdgeData(typeStr: string): string {
|
||||
switch (typeStr.trim()) {
|
||||
case '--x':
|
||||
return 'arrow_cross';
|
||||
case '--o':
|
||||
return 'arrow_circle';
|
||||
default:
|
||||
return 'arrow_point';
|
||||
}
|
||||
}
|
||||
|
||||
let cnt = 0;
|
||||
export const generateId = () => {
|
||||
cnt++;
|
||||
return 'id-' + Math.random().toString(36).substr(2, 12) + '-' + cnt;
|
||||
};
|
||||
|
||||
const setHierarchy = (block: Block[]): void => {
|
||||
rootBlock.children = block;
|
||||
populateBlockDatabase(block, rootBlock);
|
||||
blocks = rootBlock.children;
|
||||
};
|
||||
|
||||
const getColumns = (blockId: string): number => {
|
||||
const block = blockDatabase[blockId];
|
||||
if (!block) {
|
||||
return -1;
|
||||
}
|
||||
if (block.columns) {
|
||||
return block.columns;
|
||||
}
|
||||
if (!block.children) {
|
||||
return -1;
|
||||
}
|
||||
return block.children.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns all the blocks as a flat array
|
||||
* @returns
|
||||
*/
|
||||
const getBlocksFlat = () => {
|
||||
return [...Object.values(blockDatabase)];
|
||||
};
|
||||
/**
|
||||
* Returns the the hierarchy of blocks
|
||||
* @returns
|
||||
*/
|
||||
const getBlocks = () => {
|
||||
return blocks || [];
|
||||
};
|
||||
|
||||
const getEdges = () => {
|
||||
return edgeList;
|
||||
};
|
||||
const getBlock = (id: string) => {
|
||||
return blockDatabase[id];
|
||||
};
|
||||
|
||||
const setBlock = (block: Block) => {
|
||||
blockDatabase[block.id] = block;
|
||||
};
|
||||
|
||||
const getLogger = () => console;
|
||||
|
||||
/**
|
||||
* Return all of the style classes
|
||||
*/
|
||||
export const getClasses = function () {
|
||||
return classes;
|
||||
};
|
||||
|
||||
const db = {
|
||||
getConfig: () => configApi.getConfig().block,
|
||||
typeStr2Type: typeStr2Type,
|
||||
edgeTypeStr2Type: edgeTypeStr2Type,
|
||||
edgeStrToEdgeData,
|
||||
getLogger,
|
||||
getBlocksFlat,
|
||||
getBlocks,
|
||||
getEdges,
|
||||
setHierarchy,
|
||||
getBlock,
|
||||
setBlock,
|
||||
getColumns,
|
||||
getClasses,
|
||||
clear,
|
||||
generateId,
|
||||
} as const;
|
||||
|
||||
export type BlockDB = typeof db & DiagramDB;
|
||||
export default db;
|
20
packages/mermaid/src/diagrams/block/blockDetector.ts
Normal file
20
packages/mermaid/src/diagrams/block/blockDetector.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'block';
|
||||
|
||||
const detector: DiagramDetector = (txt) => {
|
||||
return /^\s*block-beta/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const { diagram } = await import('./blockDiagram.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
const plugin: ExternalDiagramDefinition = {
|
||||
id,
|
||||
detector,
|
||||
loader,
|
||||
};
|
||||
|
||||
export default plugin;
|
13
packages/mermaid/src/diagrams/block/blockDiagram.ts
Normal file
13
packages/mermaid/src/diagrams/block/blockDiagram.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import type { DiagramDefinition } from '../../diagram-api/types.js';
|
||||
// @ts-ignore: jison doesn't export types
|
||||
import parser from './parser/block.jison';
|
||||
import db from './blockDB.js';
|
||||
import flowStyles from './styles.js';
|
||||
import renderer from './blockRenderer.js';
|
||||
|
||||
export const diagram: DiagramDefinition = {
|
||||
parser,
|
||||
db,
|
||||
renderer,
|
||||
styles: flowStyles,
|
||||
};
|
96
packages/mermaid/src/diagrams/block/blockRenderer.ts
Normal file
96
packages/mermaid/src/diagrams/block/blockRenderer.ts
Normal file
@ -0,0 +1,96 @@
|
||||
import type { Diagram } from '../../Diagram.js';
|
||||
import * as configApi from '../../config.js';
|
||||
import { calculateBlockSizes, insertBlocks, insertEdges } from './renderHelpers.js';
|
||||
import { layout } from './layout.js';
|
||||
import type { MermaidConfig, BaseDiagramConfig } from '../../config.type.js';
|
||||
import insertMarkers from '../../dagre-wrapper/markers.js';
|
||||
import {
|
||||
select as d3select,
|
||||
scaleOrdinal as d3scaleOrdinal,
|
||||
schemeTableau10 as d3schemeTableau10,
|
||||
} from 'd3';
|
||||
import type { ContainerElement } from 'd3';
|
||||
import { log } from '../../logger.js';
|
||||
import type { BlockDB } from './blockDB.js';
|
||||
import type { Block } from './blockTypes.js';
|
||||
import { configureSvgSize } from '../../setupGraphViewbox.js';
|
||||
|
||||
/**
|
||||
* Returns the all the styles from classDef statements in the graph definition.
|
||||
*
|
||||
* @param text - The text with the classes
|
||||
* @param diagObj - The diagram object
|
||||
* @returns ClassDef - The styles
|
||||
*/
|
||||
export const getClasses = function (text: any, diagObj: any) {
|
||||
return diagObj.db.getClasses();
|
||||
};
|
||||
|
||||
export const draw = async function (
|
||||
text: string,
|
||||
id: string,
|
||||
_version: string,
|
||||
diagObj: Diagram
|
||||
): Promise<void> {
|
||||
const { securityLevel, block: conf } = configApi.getConfig();
|
||||
const db = diagObj.db as BlockDB;
|
||||
let sandboxElement: any;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = d3select('#i' + id);
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? d3select<HTMLBodyElement, unknown>(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: d3select<HTMLBodyElement, unknown>('body');
|
||||
|
||||
const svg =
|
||||
securityLevel === 'sandbox'
|
||||
? root.select<SVGSVGElement>(`[id="${id}"]`)
|
||||
: d3select<SVGSVGElement, unknown>(`[id="${id}"]`);
|
||||
|
||||
// Define the supported markers for the diagram
|
||||
const markers = ['point', 'circle', 'cross'];
|
||||
|
||||
// Add the marker definitions to the svg as marker tags
|
||||
// insertMarkers(svg, markers, diagObj.type, diagObj.arrowMarkerAbsolute);
|
||||
// insertMarkers(svg, markers, diagObj.type, true);
|
||||
insertMarkers(svg, markers, diagObj.type, id);
|
||||
|
||||
const bl = db.getBlocks();
|
||||
const blArr = db.getBlocksFlat();
|
||||
const edges = db.getEdges();
|
||||
|
||||
const nodes = svg.insert('g').attr('class', 'block');
|
||||
await calculateBlockSizes(nodes, bl, db);
|
||||
const bounds = layout(db);
|
||||
await insertBlocks(nodes, bl, db);
|
||||
await insertEdges(nodes, edges, blArr, db, id);
|
||||
|
||||
// log.debug('Here', bl);
|
||||
|
||||
// Establish svg dimensions and get width and height
|
||||
//
|
||||
// const bounds2 = nodes.node().getBoundingClientRect();
|
||||
// Why, oh why ????
|
||||
if (bounds) {
|
||||
const bounds2 = bounds;
|
||||
const magicFactor = Math.max(1, Math.round(0.125 * (bounds2.width / bounds2.height)));
|
||||
const height = bounds2.height + magicFactor + 10;
|
||||
const width = bounds2.width + 10;
|
||||
const { useMaxWidth } = conf as Exclude<MermaidConfig['block'], undefined>;
|
||||
configureSvgSize(svg, height, width, !!useMaxWidth);
|
||||
log.debug('Here Bounds', bounds, bounds2);
|
||||
svg.attr(
|
||||
'viewBox',
|
||||
`${bounds2.x - 5} ${bounds2.y - 5} ${bounds2.width + 10} ${bounds2.height + 10}`
|
||||
);
|
||||
}
|
||||
|
||||
// Get color scheme for the graph
|
||||
const colorScheme = d3scaleOrdinal(d3schemeTableau10);
|
||||
};
|
||||
|
||||
export default {
|
||||
draw,
|
||||
getClasses,
|
||||
};
|
68
packages/mermaid/src/diagrams/block/blockTypes.ts
Normal file
68
packages/mermaid/src/diagrams/block/blockTypes.ts
Normal file
@ -0,0 +1,68 @@
|
||||
export type { BlockDiagramConfig as BlockConfig } from '../../config.type.js';
|
||||
|
||||
export type BlockType =
|
||||
| 'na'
|
||||
| 'column-setting'
|
||||
| 'edge'
|
||||
| 'round'
|
||||
| 'block_arrow'
|
||||
| 'space'
|
||||
| 'square'
|
||||
| 'diamond'
|
||||
| 'hexagon'
|
||||
| 'odd'
|
||||
| 'lean_right'
|
||||
| 'lean_left'
|
||||
| 'trapezoid'
|
||||
| 'inv_trapezoid'
|
||||
| 'rect_left_inv_arrow'
|
||||
| 'odd_right'
|
||||
| 'circle'
|
||||
| 'ellipse'
|
||||
| 'stadium'
|
||||
| 'subroutine'
|
||||
| 'cylinder'
|
||||
| 'group'
|
||||
| 'doublecircle'
|
||||
| 'classDef'
|
||||
| 'applyClass'
|
||||
| 'applyStyles'
|
||||
| 'composite';
|
||||
|
||||
export interface Block {
|
||||
// When the block have the type edge, the start and end are the id of the source and target blocks
|
||||
start?: string;
|
||||
end?: string;
|
||||
arrowTypeEnd?: string;
|
||||
arrowTypeStart?: string;
|
||||
width?: number;
|
||||
id: string;
|
||||
label?: string;
|
||||
intersect?: any;
|
||||
parent?: Block;
|
||||
type?: BlockType;
|
||||
children: Block[];
|
||||
size?: {
|
||||
width: number;
|
||||
height: number;
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
node?: any;
|
||||
columns?: number; // | TBlockColumnsDefaultValue;
|
||||
classes?: string[];
|
||||
directions?: string[];
|
||||
css?: string;
|
||||
styleClass?: string;
|
||||
styles?: string[];
|
||||
stylesStr?: string;
|
||||
widthInColumns?: number;
|
||||
}
|
||||
|
||||
export interface ClassDef {
|
||||
id: string;
|
||||
textStyles: string[];
|
||||
styles: string[];
|
||||
}
|
||||
|
||||
export type Direction = 'up' | 'down' | 'left' | 'right' | 'x' | 'y';
|
8
packages/mermaid/src/diagrams/block/blockUtils.ts
Normal file
8
packages/mermaid/src/diagrams/block/blockUtils.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export const prepareTextForParsing = (text: string): string => {
|
||||
const textToParse = text
|
||||
.replaceAll(/^[^\S\n\r]+|[^\S\n\r]+$/g, '') // remove all trailing spaces for each row
|
||||
.replaceAll(/([\n\r])+/g, '\n') // remove empty lines duplicated
|
||||
.trim();
|
||||
|
||||
return textToParse;
|
||||
};
|
12
packages/mermaid/src/diagrams/block/layout.spec.ts
Normal file
12
packages/mermaid/src/diagrams/block/layout.spec.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { calculateBlockPosition } from './layout.js';
|
||||
|
||||
describe('Layout', function () {
|
||||
it('should calculate position correctly', () => {
|
||||
expect(calculateBlockPosition(2, 0)).toEqual({ px: 0, py: 0 });
|
||||
expect(calculateBlockPosition(2, 1)).toEqual({ px: 1, py: 0 });
|
||||
expect(calculateBlockPosition(2, 2)).toEqual({ px: 0, py: 1 });
|
||||
expect(calculateBlockPosition(2, 3)).toEqual({ px: 1, py: 1 });
|
||||
expect(calculateBlockPosition(2, 4)).toEqual({ px: 0, py: 2 });
|
||||
expect(calculateBlockPosition(1, 3)).toEqual({ px: 0, py: 3 });
|
||||
});
|
||||
});
|
329
packages/mermaid/src/diagrams/block/layout.ts
Normal file
329
packages/mermaid/src/diagrams/block/layout.ts
Normal file
@ -0,0 +1,329 @@
|
||||
import type { BlockDB } from './blockDB.js';
|
||||
import type { Block } from './blockTypes.js';
|
||||
import { log } from '../../logger.js';
|
||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
const padding = getConfig()?.block?.padding || 8;
|
||||
|
||||
interface BlockPosition {
|
||||
px: number;
|
||||
py: number;
|
||||
}
|
||||
|
||||
export function calculateBlockPosition(columns: number, position: number): BlockPosition {
|
||||
// log.debug('calculateBlockPosition abc89', columns, position);
|
||||
// Ensure that columns is a positive integer
|
||||
if (columns === 0 || !Number.isInteger(columns)) {
|
||||
throw new Error('Columns must be an integer !== 0.');
|
||||
}
|
||||
|
||||
// Ensure that position is a non-negative integer
|
||||
if (position < 0 || !Number.isInteger(position)) {
|
||||
throw new Error('Position must be a non-negative integer.' + position);
|
||||
}
|
||||
|
||||
if (columns < 0) {
|
||||
// Auto columns is set
|
||||
return { px: position, py: 0 };
|
||||
}
|
||||
if (columns === 1) {
|
||||
// Auto columns is set
|
||||
return { px: 0, py: position };
|
||||
}
|
||||
// Calculate posX and posY
|
||||
const px = position % columns;
|
||||
const py = Math.floor(position / columns);
|
||||
// log.debug('calculateBlockPosition abc89', columns, position, '=> (', px, py, ')');
|
||||
return { px, py };
|
||||
}
|
||||
|
||||
const getMaxChildSize = (block: Block) => {
|
||||
let maxWidth = 0;
|
||||
let maxHeight = 0;
|
||||
// find max width of children
|
||||
// log.debug('getMaxChildSize abc95 (start) parent:', block.id);
|
||||
for (const child of block.children) {
|
||||
const { width, height, x, y } = child.size || { width: 0, height: 0, x: 0, y: 0 };
|
||||
log.debug(
|
||||
'getMaxChildSize abc95 child:',
|
||||
child.id,
|
||||
'width:',
|
||||
width,
|
||||
'height:',
|
||||
height,
|
||||
'x:',
|
||||
x,
|
||||
'y:',
|
||||
y,
|
||||
child.type
|
||||
);
|
||||
if (child.type === 'space') {
|
||||
continue;
|
||||
}
|
||||
if (width > maxWidth) {
|
||||
maxWidth = width / (block.widthInColumns || 1);
|
||||
}
|
||||
if (height > maxHeight) {
|
||||
maxHeight = height;
|
||||
}
|
||||
}
|
||||
return { width: maxWidth, height: maxHeight };
|
||||
};
|
||||
|
||||
function setBlockSizes(block: Block, db: BlockDB, siblingWidth = 0, siblingHeight = 0) {
|
||||
log.debug(
|
||||
'setBlockSizes abc95 (start)',
|
||||
block.id,
|
||||
block?.size?.x,
|
||||
'block width =',
|
||||
block?.size,
|
||||
'sieblingWidth',
|
||||
siblingWidth
|
||||
);
|
||||
if (!block?.size?.width) {
|
||||
block.size = {
|
||||
width: siblingWidth,
|
||||
height: siblingHeight,
|
||||
x: 0,
|
||||
y: 0,
|
||||
};
|
||||
}
|
||||
let maxWidth = 0;
|
||||
let maxHeight = 0;
|
||||
|
||||
if (block.children?.length > 0) {
|
||||
for (const child of block.children) {
|
||||
setBlockSizes(child, db);
|
||||
}
|
||||
// find max width of children
|
||||
const childSize = getMaxChildSize(block);
|
||||
maxWidth = childSize.width;
|
||||
maxHeight = childSize.height;
|
||||
log.debug('setBlockSizes abc95 maxWidth of', block.id, ':s children is ', maxWidth, maxHeight);
|
||||
|
||||
// set width of block to max width of children
|
||||
for (const child of block.children) {
|
||||
if (child.size) {
|
||||
log.debug(
|
||||
`abc95 Setting size of children of ${block.id} id=${child.id} ${maxWidth} ${maxHeight} ${child.size}`
|
||||
);
|
||||
child.size.width =
|
||||
maxWidth * (child.widthInColumns || 1) + padding * ((child.widthInColumns || 1) - 1);
|
||||
child.size.height = maxHeight;
|
||||
child.size.x = 0;
|
||||
child.size.y = 0;
|
||||
|
||||
log.debug(
|
||||
`abc95 updating size of ${block.id} children child:${child.id} maxWidth:${maxWidth} maxHeight:${maxHeight}`
|
||||
);
|
||||
}
|
||||
}
|
||||
for (const child of block.children) {
|
||||
setBlockSizes(child, db, maxWidth, maxHeight);
|
||||
}
|
||||
|
||||
const columns = block.columns || -1;
|
||||
let numItems = 0;
|
||||
for (const child of block.children) {
|
||||
numItems += child.widthInColumns || 1;
|
||||
}
|
||||
|
||||
// The width and height in number blocks
|
||||
let xSize = block.children.length;
|
||||
if (columns > 0 && columns < numItems) {
|
||||
xSize = columns;
|
||||
}
|
||||
|
||||
const w = block.widthInColumns || 1;
|
||||
|
||||
const ySize = Math.ceil(numItems / xSize);
|
||||
|
||||
let width = xSize * (maxWidth + padding) + padding;
|
||||
let height = ySize * (maxHeight + padding) + padding;
|
||||
// If maxWidth
|
||||
if (width < siblingWidth) {
|
||||
log.debug(
|
||||
`Detected to small siebling: abc95 ${block.id} sieblingWidth ${siblingWidth} sieblingHeight ${siblingHeight} width ${width}`
|
||||
);
|
||||
width = siblingWidth;
|
||||
height = siblingHeight;
|
||||
const childWidth = (siblingWidth - xSize * padding - padding) / xSize;
|
||||
const childHeight = (siblingHeight - ySize * padding - padding) / ySize;
|
||||
// cspell:ignore indata
|
||||
log.debug('Size indata abc88', block.id, 'childWidth', childWidth, 'maxWidth', maxWidth);
|
||||
log.debug('Size indata abc88', block.id, 'childHeight', childHeight, 'maxHeight', maxHeight);
|
||||
log.debug('Size indata abc88 xSize', xSize, 'padding', padding);
|
||||
|
||||
// set width of block to max width of children
|
||||
for (const child of block.children) {
|
||||
if (child.size) {
|
||||
child.size.width = childWidth;
|
||||
child.size.height = childHeight;
|
||||
child.size.x = 0;
|
||||
child.size.y = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.debug(
|
||||
`abc95 (finale calc) ${block.id} xSize ${xSize} ySize ${ySize} columns ${columns}${
|
||||
block.children.length
|
||||
} width=${Math.max(width, block.size?.width || 0)}`
|
||||
);
|
||||
if (width < (block?.size?.width || 0)) {
|
||||
width = block?.size?.width || 0;
|
||||
|
||||
// Grow children to fit
|
||||
const num = columns > 0 ? Math.min(block.children.length, columns) : block.children.length;
|
||||
if (num > 0) {
|
||||
const childWidth = (width - num * padding - padding) / num;
|
||||
log.debug('abc95 (growing to fit) width', block.id, width, block.size?.width, childWidth);
|
||||
for (const child of block.children) {
|
||||
if (child.size) {
|
||||
child.size.width = childWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
block.size = {
|
||||
width,
|
||||
height,
|
||||
x: 0,
|
||||
y: 0,
|
||||
};
|
||||
}
|
||||
|
||||
log.debug(
|
||||
'setBlockSizes abc94 (done)',
|
||||
block.id,
|
||||
block?.size?.x,
|
||||
block?.size?.width,
|
||||
block?.size?.y,
|
||||
block?.size?.height
|
||||
);
|
||||
}
|
||||
|
||||
function layoutBlocks(block: Block, db: BlockDB) {
|
||||
log.debug(
|
||||
`abc85 layout blocks (=>layoutBlocks) ${block.id} x: ${block?.size?.x} y: ${block?.size?.y} width: ${block?.size?.width}`
|
||||
);
|
||||
const columns = block.columns || -1;
|
||||
log.debug('layoutBlocks columns abc95', block.id, '=>', columns, block);
|
||||
if (
|
||||
block.children && // find max width of children
|
||||
block.children.length > 0
|
||||
) {
|
||||
const width = block?.children[0]?.size?.width || 0;
|
||||
const widthOfChildren = block.children.length * width + (block.children.length - 1) * padding;
|
||||
|
||||
log.debug('widthOfChildren 88', widthOfChildren, 'posX');
|
||||
|
||||
// let first = true;
|
||||
let columnPos = 0;
|
||||
log.debug('abc91 block?.size?.x', block.id, block?.size?.x);
|
||||
let startingPosX = block?.size?.x ? block?.size?.x + (-block?.size?.width / 2 || 0) : -padding;
|
||||
let rowPos = 0;
|
||||
for (const child of block.children) {
|
||||
const parent = block;
|
||||
|
||||
if (!child.size) {
|
||||
continue;
|
||||
}
|
||||
const { width, height } = child.size;
|
||||
const { px, py } = calculateBlockPosition(columns, columnPos);
|
||||
if (py != rowPos) {
|
||||
rowPos = py;
|
||||
startingPosX = block?.size?.x ? block?.size?.x + (-block?.size?.width / 2 || 0) : -padding;
|
||||
log.debug('New row in layout for block', block.id, ' and child ', child.id, rowPos);
|
||||
}
|
||||
log.debug(
|
||||
`abc89 layout blocks (child) id: ${child.id} Pos: ${columnPos} (px, py) ${px},${py} (${parent?.size?.x},${parent?.size?.y}) parent: ${parent.id} width: ${width}${padding}`
|
||||
);
|
||||
if (parent.size) {
|
||||
const halfWidth = width / 2;
|
||||
child.size.x = startingPosX + padding + halfWidth;
|
||||
|
||||
// cspell:ignore pyid
|
||||
log.debug(
|
||||
`abc91 layout blocks (calc) px, pyid:${
|
||||
child.id
|
||||
} startingPos=X${startingPosX} new startingPosX${
|
||||
child.size.x
|
||||
} ${halfWidth} padding=${padding} width=${width} halfWidth=${halfWidth} => x:${
|
||||
child.size.x
|
||||
} y:${child.size.y} ${child.widthInColumns} (width * (child?.w || 1)) / 2 ${
|
||||
(width * (child?.widthInColumns || 1)) / 2
|
||||
}`
|
||||
);
|
||||
|
||||
startingPosX = child.size.x + halfWidth;
|
||||
|
||||
child.size.y =
|
||||
parent.size.y - parent.size.height / 2 + py * (height + padding) + height / 2 + padding;
|
||||
|
||||
log.debug(
|
||||
`abc88 layout blocks (calc) px, pyid:${
|
||||
child.id
|
||||
}startingPosX${startingPosX}${padding}${halfWidth}=>x:${child.size.x}y:${child.size.y}${
|
||||
child.widthInColumns
|
||||
}(width * (child?.w || 1)) / 2${(width * (child?.widthInColumns || 1)) / 2}`
|
||||
);
|
||||
}
|
||||
|
||||
// posY += height + padding;
|
||||
if (child.children) {
|
||||
layoutBlocks(child, db);
|
||||
}
|
||||
columnPos += child?.widthInColumns || 1;
|
||||
log.debug('abc88 columnsPos', child, columnPos);
|
||||
}
|
||||
}
|
||||
log.debug(
|
||||
`layout blocks (<==layoutBlocks) ${block.id} x: ${block?.size?.x} y: ${block?.size?.y} width: ${block?.size?.width}`
|
||||
);
|
||||
}
|
||||
|
||||
function findBounds(
|
||||
block: Block,
|
||||
{ minX, minY, maxX, maxY } = { minX: 0, minY: 0, maxX: 0, maxY: 0 }
|
||||
) {
|
||||
if (block.size && block.id !== 'root') {
|
||||
const { x, y, width, height } = block.size;
|
||||
if (x - width / 2 < minX) {
|
||||
minX = x - width / 2;
|
||||
}
|
||||
if (y - height / 2 < minY) {
|
||||
minY = y - height / 2;
|
||||
}
|
||||
if (x + width / 2 > maxX) {
|
||||
maxX = x + width / 2;
|
||||
}
|
||||
if (y + height / 2 > maxY) {
|
||||
maxY = y + height / 2;
|
||||
}
|
||||
}
|
||||
if (block.children) {
|
||||
for (const child of block.children) {
|
||||
({ minX, minY, maxX, maxY } = findBounds(child, { minX, minY, maxX, maxY }));
|
||||
}
|
||||
}
|
||||
return { minX, minY, maxX, maxY };
|
||||
}
|
||||
|
||||
export function layout(db: BlockDB) {
|
||||
const root = db.getBlock('root');
|
||||
if (!root) {
|
||||
return;
|
||||
}
|
||||
|
||||
setBlockSizes(root, db, 0, 0);
|
||||
layoutBlocks(root, db);
|
||||
// Position blocks relative to parents
|
||||
// positionBlock(root, root, db);
|
||||
log.debug('getBlocks', JSON.stringify(root, null, 2));
|
||||
|
||||
const { minX, minY, maxX, maxY } = findBounds(root);
|
||||
|
||||
const height = maxY - minY;
|
||||
const width = maxX - minX;
|
||||
return { x: minX, y: minY, width, height };
|
||||
}
|
290
packages/mermaid/src/diagrams/block/parser/block.jison
Normal file
290
packages/mermaid/src/diagrams/block/parser/block.jison
Normal file
@ -0,0 +1,290 @@
|
||||
/** mermaid */
|
||||
|
||||
//---------------------------------------------------------
|
||||
// We support csv format as defined here:
|
||||
// https://www.ietf.org/rfc/rfc4180.txt
|
||||
// There are some minor changes for compliance with jison
|
||||
// We also parse only 3 columns: source,target,value
|
||||
// And allow blank lines for visual purposes
|
||||
//---------------------------------------------------------
|
||||
|
||||
%lex
|
||||
%x acc_title
|
||||
%x acc_descr
|
||||
%x acc_descr_multiline
|
||||
%x string
|
||||
%x space
|
||||
%x md_string
|
||||
%x NODE
|
||||
%x BLOCK_ARROW
|
||||
%x ARROW_DIR
|
||||
%x LLABEL
|
||||
%x CLASS
|
||||
%x CLASS_STYLE
|
||||
%x CLASSDEF
|
||||
%x CLASSDEFID
|
||||
%x STYLE_STMNT
|
||||
%x STYLE_DEFINITION
|
||||
|
||||
|
||||
// as per section 6.1 of RFC 2234 [2]
|
||||
COMMA \u002C
|
||||
CR \u000D
|
||||
LF \u000A
|
||||
CRLF \u000D\u000A
|
||||
|
||||
|
||||
%%
|
||||
|
||||
"block-beta" { return 'BLOCK_DIAGRAM_KEY'; }
|
||||
"block"\s+ { yy.getLogger().debug('Found space-block'); return 'block';}
|
||||
"block"\n+ { yy.getLogger().debug('Found nl-block'); return 'block';}
|
||||
"block:" { yy.getLogger().debug('Found space-block'); return 'id-block';}
|
||||
// \s*\%\%.* { yy.getLogger().debug('Found comment',yytext); }
|
||||
[\s]+ { yy.getLogger().debug('.', yytext); /* skip all whitespace */ }
|
||||
[\n]+ {yy.getLogger().debug('_', yytext); /* skip all whitespace */ }
|
||||
// [\n] return 'NL';
|
||||
<INITIAL>({CRLF}|{LF}) { return 'NL' }
|
||||
"columns"\s+"auto" { yytext=-1; return 'COLUMNS'; }
|
||||
"columns"\s+[\d]+ { yytext = yytext.replace(/columns\s+/,''); yy.getLogger().debug('COLUMNS (LEX)', yytext); return 'COLUMNS'; }
|
||||
["][`] { this.pushState("md_string");}
|
||||
<md_string>[^`"]+ { return "MD_STR";}
|
||||
<md_string>[`]["] { this.popState();}
|
||||
["] this.pushState("string");
|
||||
<string>["] { yy.getLogger().debug('LEX: POPPING STR:', yytext);this.popState();}
|
||||
<string>[^"]* { yy.getLogger().debug('LEX: STR end:', yytext); return "STR";}
|
||||
space[:]\d+ { yytext = yytext.replace(/space\:/,'');yy.getLogger().debug('SPACE NUM (LEX)', yytext); return 'SPACE_BLOCK'; }
|
||||
space { yytext = '1'; yy.getLogger().debug('COLUMNS (LEX)', yytext); return 'SPACE_BLOCK'; }
|
||||
"default" return 'DEFAULT';
|
||||
"linkStyle" return 'LINKSTYLE';
|
||||
"interpolate" return 'INTERPOLATE';
|
||||
|
||||
"classDef"\s+ { this.pushState('CLASSDEF'); return 'classDef'; }
|
||||
<CLASSDEF>DEFAULT\s+ { this.popState(); this.pushState('CLASSDEFID'); return 'DEFAULT_CLASSDEF_ID' }
|
||||
<CLASSDEF>\w+\s+ { this.popState(); this.pushState('CLASSDEFID'); return 'CLASSDEF_ID' }
|
||||
<CLASSDEFID>[^\n]* { this.popState(); return 'CLASSDEF_STYLEOPTS' }
|
||||
|
||||
"class"\s+ { this.pushState('CLASS'); return 'class'; }
|
||||
<CLASS>(\w+)+((","\s*\w+)*) { this.popState(); this.pushState('CLASS_STYLE'); return 'CLASSENTITY_IDS' }
|
||||
<CLASS_STYLE>[^\n]* { this.popState(); return 'STYLECLASS' }
|
||||
|
||||
"style"\s+ { this.pushState('STYLE_STMNT'); return 'style'; }
|
||||
<STYLE_STMNT>(\w+)+((","\s*\w+)*) { this.popState(); this.pushState('STYLE_DEFINITION'); return 'STYLE_ENTITY_IDS' }
|
||||
<STYLE_DEFINITION>[^\n]* { this.popState(); return 'STYLE_DEFINITION_DATA' }
|
||||
|
||||
accTitle\s*":"\s* { this.pushState("acc_title");return 'acc_title'; }
|
||||
<acc_title>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_title_value"; }
|
||||
accDescr\s*":"\s* { this.pushState("acc_descr");return 'acc_descr'; }
|
||||
<acc_descr>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_descr_value"; }
|
||||
accDescr\s*"{"\s* { this.pushState("acc_descr_multiline");}
|
||||
<acc_descr_multiline>[\}] { this.popState(); }
|
||||
<acc_descr_multiline>[^\}]* return "acc_descr_multiline_value";
|
||||
"end"\b\s* return 'end';
|
||||
|
||||
// Node end of shape
|
||||
<NODE>"(((" { this.popState();yy.getLogger().debug('Lex: (('); return "NODE_DEND"; }
|
||||
<NODE>")))" { this.popState();yy.getLogger().debug('Lex: (('); return "NODE_DEND"; }
|
||||
<NODE>[\)]\) { this.popState();yy.getLogger().debug('Lex: ))'); return "NODE_DEND"; }
|
||||
<NODE>"}}" { this.popState();yy.getLogger().debug('Lex: (('); return "NODE_DEND"; }
|
||||
<NODE>"}" { this.popState();yy.getLogger().debug('Lex: (('); return "NODE_DEND"; }
|
||||
<NODE>"(-" { this.popState();yy.getLogger().debug('Lex: (-'); return "NODE_DEND"; }
|
||||
<NODE>"-)" { this.popState();yy.getLogger().debug('Lex: -)'); return "NODE_DEND"; }
|
||||
<NODE>"((" { this.popState();yy.getLogger().debug('Lex: (('); return "NODE_DEND"; }
|
||||
<NODE>"]]" { this.popState();yy.getLogger().debug('Lex: ]]'); return "NODE_DEND"; }
|
||||
<NODE>"(" { this.popState();yy.getLogger().debug('Lex: ('); return "NODE_DEND"; }
|
||||
<NODE>"])" { this.popState();yy.getLogger().debug('Lex: ])'); return "NODE_DEND"; }
|
||||
<NODE>"\\]" { this.popState();yy.getLogger().debug('Lex: /]'); return "NODE_DEND"; }
|
||||
<NODE>"/]" { this.popState();yy.getLogger().debug('Lex: /]'); return "NODE_DEND"; }
|
||||
<NODE>")]" { this.popState();yy.getLogger().debug('Lex: )]'); return "NODE_DEND"; }
|
||||
<NODE>[\)] { this.popState();yy.getLogger().debug('Lex: )'); return "NODE_DEND"; }
|
||||
<NODE>\]\> { this.popState();yy.getLogger().debug('Lex: ]>'); return "NODE_DEND"; }
|
||||
<NODE>[\]] { this.popState();yy.getLogger().debug('Lex: ]'); return "NODE_DEND"; }
|
||||
|
||||
// Start of nodes with shapes and description
|
||||
"-)" { yy.getLogger().debug('Lexa: -)'); this.pushState('NODE');return 'NODE_DSTART'; }
|
||||
"(-" { yy.getLogger().debug('Lexa: (-'); this.pushState('NODE');return 'NODE_DSTART'; }
|
||||
"))" { yy.getLogger().debug('Lexa: ))'); this.pushState('NODE');return 'NODE_DSTART'; }
|
||||
")" { yy.getLogger().debug('Lexa: )'); this.pushState('NODE');return 'NODE_DSTART'; }
|
||||
"(((" { yy.getLogger().debug('Lex: ((('); this.pushState('NODE');return 'NODE_DSTART'; }
|
||||
"((" { yy.getLogger().debug('Lexa: )'); this.pushState('NODE');return 'NODE_DSTART'; }
|
||||
"{{" { yy.getLogger().debug('Lexa: )'); this.pushState('NODE');return 'NODE_DSTART'; }
|
||||
"{" { yy.getLogger().debug('Lexa: )'); this.pushState('NODE');return 'NODE_DSTART'; }
|
||||
">" { yy.getLogger().debug('Lexc: >'); this.pushState('NODE');return 'NODE_DSTART'; }
|
||||
"([" { yy.getLogger().debug('Lexa: (['); this.pushState('NODE');return 'NODE_DSTART'; }
|
||||
"(" { yy.getLogger().debug('Lexa: )'); this.pushState('NODE');return 'NODE_DSTART'; }
|
||||
"[[" { this.pushState('NODE');return 'NODE_DSTART'; }
|
||||
"[|" { this.pushState('NODE');return 'NODE_DSTART'; }
|
||||
"[(" { this.pushState('NODE');return 'NODE_DSTART'; }
|
||||
")))" { this.pushState('NODE');return 'NODE_DSTART'; }
|
||||
"[\\" { this.pushState('NODE');return 'NODE_DSTART'; }
|
||||
"[/" { this.pushState('NODE');return 'NODE_DSTART'; }
|
||||
"[\\" { this.pushState('NODE');return 'NODE_DSTART'; }
|
||||
"[" { yy.getLogger().debug('Lexa: ['); this.pushState('NODE');return 'NODE_DSTART'; }
|
||||
|
||||
"<[" { this.pushState('BLOCK_ARROW');yy.getLogger().debug('LEX ARR START');return 'BLOCK_ARROW_START'; }
|
||||
|
||||
[^\(\[\n\-\)\{\}\s\<\>:]+ { yy.getLogger().debug('Lex: NODE_ID', yytext);return 'NODE_ID'; }
|
||||
<<EOF>> { yy.getLogger().debug('Lex: EOF', yytext);return 'EOF'; }
|
||||
|
||||
// Handling of strings in node
|
||||
<BLOCK_ARROW>["][`] { this.pushState("md_string");}
|
||||
<NODE>["][`] { this.pushState("md_string");}
|
||||
<md_string>[^`"]+ { return "NODE_DESCR";}
|
||||
<md_string>[`]["] { this.popState();}
|
||||
<NODE>["] { yy.getLogger().debug('Lex: Starting string');this.pushState("string");}
|
||||
<BLOCK_ARROW>["] { yy.getLogger().debug('LEX ARR: Starting string');this.pushState("string");}
|
||||
<string>[^"]+ { yy.getLogger().debug('LEX: NODE_DESCR:', yytext); return "NODE_DESCR";}
|
||||
<string>["] {yy.getLogger().debug('LEX POPPING');this.popState();}
|
||||
|
||||
<BLOCK_ARROW>"]>"\s*"(" { yy.getLogger().debug('Lex: =>BAE'); this.pushState('ARROW_DIR'); }
|
||||
<ARROW_DIR>","?\s*right\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (right): dir:',yytext);return "DIR"; }
|
||||
<ARROW_DIR>","?\s*left\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (left):',yytext);return "DIR"; }
|
||||
<ARROW_DIR>","?\s*x\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (x):',yytext); return "DIR"; }
|
||||
<ARROW_DIR>","?\s*y\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (y):',yytext); return "DIR"; }
|
||||
<ARROW_DIR>","?\s*up\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (up):',yytext); return "DIR"; }
|
||||
<ARROW_DIR>","?\s*down\s* { yytext = yytext.replace(/^,\s*/, ''); yy.getLogger().debug('Lex (down):',yytext); return "DIR"; }
|
||||
<ARROW_DIR>")"\s* { yytext=']>';yy.getLogger().debug('Lex (ARROW_DIR end):',yytext);this.popState();this.popState();return "BLOCK_ARROW_END"; }
|
||||
|
||||
// Edges
|
||||
\s*[xo<]?\-\-+[-xo>]\s* { yy.getLogger().debug('Lex: LINK', '#'+yytext+'#'); return 'LINK'; }
|
||||
\s*[xo<]?\=\=+[=xo>]\s* { yy.getLogger().debug('Lex: LINK', yytext); return 'LINK'; }
|
||||
\s*[xo<]?\-?\.+\-[xo>]?\s* { yy.getLogger().debug('Lex: LINK', yytext); return 'LINK'; }
|
||||
\s*\~\~[\~]+\s* { yy.getLogger().debug('Lex: LINK', yytext); return 'LINK'; }
|
||||
\s*[xo<]?\-\-\s* { yy.getLogger().debug('Lex: START_LINK', yytext);this.pushState("LLABEL");return 'START_LINK'; }
|
||||
\s*[xo<]?\=\=\s* { yy.getLogger().debug('Lex: START_LINK', yytext);this.pushState("LLABEL");return 'START_LINK'; }
|
||||
\s*[xo<]?\-\.\s* { yy.getLogger().debug('Lex: START_LINK', yytext);this.pushState("LLABEL");return 'START_LINK'; }
|
||||
<LLABEL>["][`] { this.pushState("md_string");}
|
||||
<LLABEL>["] { yy.getLogger().debug('Lex: Starting string');this.pushState("string"); return "LINK_LABEL";}
|
||||
<LLABEL>\s*[xo<]?\-\-+[-xo>]\s* { this.popState(); yy.getLogger().debug('Lex: LINK', '#'+yytext+'#'); return 'LINK'; }
|
||||
<LLABEL>\s*[xo<]?\=\=+[=xo>]\s* { this.popState(); yy.getLogger().debug('Lex: LINK', yytext); return 'LINK'; }
|
||||
<LLABEL>\s*[xo<]?\-?\.+\-[xo>]?\s* { this.popState(); yy.getLogger().debug('Lex: LINK', yytext); return 'LINK'; }
|
||||
':'\d+ { yy.getLogger().debug('Lex: COLON', yytext); yytext=yytext.slice(1);return 'SIZE'; }
|
||||
|
||||
/lex
|
||||
|
||||
%left '^'
|
||||
%start start
|
||||
|
||||
%% // language grammar
|
||||
|
||||
spaceLines
|
||||
: SPACELINE
|
||||
| spaceLines SPACELINE
|
||||
| spaceLines NL
|
||||
;
|
||||
|
||||
separator
|
||||
: NL
|
||||
{yy.getLogger().debug('Rule: separator (NL) ');}
|
||||
| SPACE
|
||||
{yy.getLogger().debug('Rule: separator (Space) ');}
|
||||
| EOF
|
||||
{yy.getLogger().debug('Rule: separator (EOF) ');}
|
||||
;
|
||||
|
||||
start: BLOCK_DIAGRAM_KEY document EOF
|
||||
{ yy.getLogger().debug("Rule: hierarchy: ", $2); yy.setHierarchy($2); }
|
||||
;
|
||||
|
||||
|
||||
stop
|
||||
: NL {yy.getLogger().debug('Stop NL ');}
|
||||
| EOF {yy.getLogger().debug('Stop EOF ');}
|
||||
// | SPACELINE
|
||||
| stop NL {yy.getLogger().debug('Stop NL2 ');}
|
||||
| stop EOF {yy.getLogger().debug('Stop EOF2 ');}
|
||||
;
|
||||
|
||||
//array of statements
|
||||
document
|
||||
: statement { yy.getLogger().debug("Rule: statement: ", $1); typeof $1.length === 'number'?$$ = $1:$$ = [$1]; }
|
||||
| statement document { yy.getLogger().debug("Rule: statement #2: ", $1); $$ = [$1].concat($2); }
|
||||
;
|
||||
|
||||
link
|
||||
: LINK
|
||||
{ yy.getLogger().debug("Rule: link: ", $1, yytext); $$={edgeTypeStr: $1, label:''}; }
|
||||
| START_LINK LINK_LABEL STR LINK
|
||||
{ yy.getLogger().debug("Rule: LABEL link: ", $1, $3, $4); $$={edgeTypeStr: $4, label:$3}; }
|
||||
;
|
||||
|
||||
statement
|
||||
: nodeStatement
|
||||
| columnsStatement
|
||||
| SPACE_BLOCK
|
||||
{ const num=parseInt($1); const spaceId = yy.generateId(); $$ = { id: spaceId, type:'space', label:'', width: num, children: [] }}
|
||||
| blockStatement
|
||||
| classDefStatement
|
||||
| cssClassStatement
|
||||
| styleStatement
|
||||
;
|
||||
|
||||
nodeStatement
|
||||
: nodeStatement link node {
|
||||
yy.getLogger().debug('Rule: (nodeStatement link node) ', $1, $2, $3, ' typestr: ',$2.edgeTypeStr);
|
||||
const edgeData = yy.edgeStrToEdgeData($2.edgeTypeStr)
|
||||
$$ = [
|
||||
{id: $1.id, label: $1.label, type:$1.type, directions: $1.directions},
|
||||
{id: $1.id + '-' + $3.id, start: $1.id, end: $3.id, label: $2.label, type: 'edge', directions: $3.directions, arrowTypeEnd: edgeData, arrowTypeStart: 'arrow_open' },
|
||||
{id: $3.id, label: $3.label, type: yy.typeStr2Type($3.typeStr), directions: $3.directions}
|
||||
];
|
||||
}
|
||||
| node SIZE { yy.getLogger().debug('Rule: nodeStatement (abc88 node size) ', $1, $2); $$ = {id: $1.id, label: $1.label, type: yy.typeStr2Type($1.typeStr), directions: $1.directions, widthInColumns: parseInt($2,10)}; }
|
||||
| node { yy.getLogger().debug('Rule: nodeStatement (node) ', $1); $$ = {id: $1.id, label: $1.label, type: yy.typeStr2Type($1.typeStr), directions: $1.directions, widthInColumns:1}; }
|
||||
;
|
||||
|
||||
|
||||
columnsStatement
|
||||
: COLUMNS { yy.getLogger().debug('APA123', this? this:'na'); yy.getLogger().debug("COLUMNS: ", $1); $$ = {type: 'column-setting', columns: $1 === 'auto'?-1:parseInt($1) } }
|
||||
;
|
||||
|
||||
blockStatement
|
||||
: id-block nodeStatement document end { yy.getLogger().debug('Rule: id-block statement : ', $2, $3); const id2 = yy.generateId(); $$ = { ...$2, type:'composite', children: $3 }; }
|
||||
| block document end { yy.getLogger().debug('Rule: blockStatement : ', $1, $2, $3); const id = yy.generateId(); $$ = { id, type:'composite', label:'', children: $2 }; }
|
||||
;
|
||||
|
||||
node
|
||||
: NODE_ID
|
||||
{ yy.getLogger().debug("Rule: node (NODE_ID separator): ", $1); $$ = { id: $1 }; }
|
||||
| NODE_ID nodeShapeNLabel
|
||||
{
|
||||
yy.getLogger().debug("Rule: node (NODE_ID nodeShapeNLabel separator): ", $1, $2);
|
||||
$$ = { id: $1, label: $2.label, typeStr: $2.typeStr, directions: $2.directions };
|
||||
}
|
||||
;
|
||||
|
||||
dirList: DIR { yy.getLogger().debug("Rule: dirList: ", $1); $$ = [$1]; }
|
||||
| DIR dirList { yy.getLogger().debug("Rule: dirList: ", $1, $2); $$ = [$1].concat($2); }
|
||||
;
|
||||
|
||||
nodeShapeNLabel
|
||||
: NODE_DSTART STR NODE_DEND
|
||||
{ yy.getLogger().debug("Rule: nodeShapeNLabel: ", $1, $2, $3); $$ = { typeStr: $1 + $3, label: $2 }; }
|
||||
| BLOCK_ARROW_START STR dirList BLOCK_ARROW_END
|
||||
{ yy.getLogger().debug("Rule: BLOCK_ARROW nodeShapeNLabel: ", $1, $2, " #3:",$3, $4); $$ = { typeStr: $1 + $4, label: $2, directions: $3}; }
|
||||
;
|
||||
|
||||
|
||||
classDefStatement
|
||||
: classDef CLASSDEF_ID CLASSDEF_STYLEOPTS {
|
||||
$$ = { type: 'classDef', id: $2.trim(), css: $3.trim() };
|
||||
}
|
||||
| classDef DEFAULT CLASSDEF_STYLEOPTS {
|
||||
$$ = { type: 'classDef', id: $2.trim(), css: $3.trim() };
|
||||
}
|
||||
;
|
||||
|
||||
cssClassStatement
|
||||
: class CLASSENTITY_IDS STYLECLASS {
|
||||
//log.debug('apply class: id(s): ',$2, ' style class: ', $3);
|
||||
$$={ type: 'applyClass', id: $2.trim(), styleClass: $3.trim() };
|
||||
}
|
||||
;
|
||||
|
||||
styleStatement
|
||||
: style STYLE_ENTITY_IDS STYLE_DEFINITION_DATA {
|
||||
$$={ type: 'applyStyles', id: $2.trim(), stylesStr: $3.trim() };
|
||||
}
|
||||
;
|
||||
|
||||
%%
|
409
packages/mermaid/src/diagrams/block/parser/block.spec.ts
Normal file
409
packages/mermaid/src/diagrams/block/parser/block.spec.ts
Normal file
@ -0,0 +1,409 @@
|
||||
// @ts-ignore: jison doesn't export types
|
||||
import block from './block.jison';
|
||||
import db from '../blockDB.js';
|
||||
import { cleanupComments } from '../../../diagram-api/comments.js';
|
||||
import { prepareTextForParsing } from '../blockUtils.js';
|
||||
import { setConfig } from '../../../config.js';
|
||||
|
||||
describe('Block diagram', function () {
|
||||
describe('when parsing an block diagram graph it should handle > ', function () {
|
||||
beforeEach(function () {
|
||||
block.parser.yy = db;
|
||||
block.parser.yy.clear();
|
||||
block.parser.yy.getLogger = () => console;
|
||||
});
|
||||
|
||||
it('a diagram with a node', async () => {
|
||||
const str = `block-beta
|
||||
id
|
||||
`;
|
||||
|
||||
block.parse(str);
|
||||
const blocks = db.getBlocks();
|
||||
expect(blocks.length).toBe(1);
|
||||
expect(blocks[0].id).toBe('id');
|
||||
expect(blocks[0].label).toBe('id');
|
||||
});
|
||||
it('a node with a square shape and a label', async () => {
|
||||
const str = `block-beta
|
||||
id["A label"]
|
||||
`;
|
||||
|
||||
block.parse(str);
|
||||
const blocks = db.getBlocks();
|
||||
expect(blocks.length).toBe(1);
|
||||
expect(blocks[0].id).toBe('id');
|
||||
expect(blocks[0].label).toBe('A label');
|
||||
expect(blocks[0].type).toBe('square');
|
||||
});
|
||||
it('a diagram with multiple nodes', async () => {
|
||||
const str = `block-beta
|
||||
id1
|
||||
id2
|
||||
`;
|
||||
|
||||
block.parse(str);
|
||||
const blocks = db.getBlocks();
|
||||
expect(blocks.length).toBe(2);
|
||||
expect(blocks[0].id).toBe('id1');
|
||||
expect(blocks[0].label).toBe('id1');
|
||||
expect(blocks[0].type).toBe('na');
|
||||
expect(blocks[1].id).toBe('id2');
|
||||
expect(blocks[1].label).toBe('id2');
|
||||
expect(blocks[1].type).toBe('na');
|
||||
});
|
||||
it('a diagram with multiple nodes', async () => {
|
||||
const str = `block-beta
|
||||
id1
|
||||
id2
|
||||
id3
|
||||
`;
|
||||
|
||||
block.parse(str);
|
||||
const blocks = db.getBlocks();
|
||||
expect(blocks.length).toBe(3);
|
||||
expect(blocks[0].id).toBe('id1');
|
||||
expect(blocks[0].label).toBe('id1');
|
||||
expect(blocks[0].type).toBe('na');
|
||||
expect(blocks[1].id).toBe('id2');
|
||||
expect(blocks[1].label).toBe('id2');
|
||||
expect(blocks[1].type).toBe('na');
|
||||
expect(blocks[2].id).toBe('id3');
|
||||
expect(blocks[2].label).toBe('id3');
|
||||
expect(blocks[2].type).toBe('na');
|
||||
});
|
||||
|
||||
it('a node with a square shape and a label', async () => {
|
||||
const str = `block-beta
|
||||
id["A label"]
|
||||
id2`;
|
||||
|
||||
block.parse(str);
|
||||
const blocks = db.getBlocks();
|
||||
expect(blocks.length).toBe(2);
|
||||
expect(blocks[0].id).toBe('id');
|
||||
expect(blocks[0].label).toBe('A label');
|
||||
expect(blocks[0].type).toBe('square');
|
||||
expect(blocks[1].id).toBe('id2');
|
||||
expect(blocks[1].label).toBe('id2');
|
||||
expect(blocks[1].type).toBe('na');
|
||||
});
|
||||
it('a diagram with multiple nodes with edges abc123', async () => {
|
||||
const str = `block-beta
|
||||
id1["first"] --> id2["second"]
|
||||
`;
|
||||
|
||||
block.parse(str);
|
||||
const blocks = db.getBlocks();
|
||||
const edges = db.getEdges();
|
||||
expect(blocks.length).toBe(2);
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('id1');
|
||||
expect(edges[0].end).toBe('id2');
|
||||
expect(edges[0].arrowTypeEnd).toBe('arrow_point');
|
||||
});
|
||||
it('a diagram with multiple nodes with edges abc123', async () => {
|
||||
const str = `block-beta
|
||||
id1["first"] -- "a label" --> id2["second"]
|
||||
`;
|
||||
|
||||
block.parse(str);
|
||||
const blocks = db.getBlocks();
|
||||
const edges = db.getEdges();
|
||||
expect(blocks.length).toBe(2);
|
||||
expect(edges.length).toBe(1);
|
||||
expect(edges[0].start).toBe('id1');
|
||||
expect(edges[0].end).toBe('id2');
|
||||
expect(edges[0].arrowTypeEnd).toBe('arrow_point');
|
||||
expect(edges[0].label).toBe('a label');
|
||||
});
|
||||
it('a diagram with column statements', async () => {
|
||||
const str = `block-beta
|
||||
columns 2
|
||||
block1["Block 1"]
|
||||
`;
|
||||
|
||||
block.parse(str);
|
||||
expect(db.getColumns('root')).toBe(2);
|
||||
const blocks = db.getBlocks();
|
||||
expect(blocks.length).toBe(1);
|
||||
});
|
||||
it('a diagram withput column statements', async () => {
|
||||
const str = `block-beta
|
||||
block1["Block 1"]
|
||||
`;
|
||||
|
||||
block.parse(str);
|
||||
expect(db.getColumns('root')).toBe(-1);
|
||||
const blocks = db.getBlocks();
|
||||
expect(blocks.length).toBe(1);
|
||||
});
|
||||
it('a diagram with auto column statements', async () => {
|
||||
const str = `block-beta
|
||||
columns auto
|
||||
block1["Block 1"]
|
||||
`;
|
||||
|
||||
block.parse(str);
|
||||
expect(db.getColumns('root')).toBe(-1);
|
||||
const blocks = db.getBlocks();
|
||||
expect(blocks.length).toBe(1);
|
||||
});
|
||||
|
||||
it('blocks next to each other', async () => {
|
||||
const str = `block-beta
|
||||
columns 2
|
||||
block1["Block 1"]
|
||||
block2["Block 2"]
|
||||
`;
|
||||
|
||||
block.parse(str);
|
||||
|
||||
const blocks = db.getBlocks();
|
||||
expect(db.getColumns('root')).toBe(2);
|
||||
expect(blocks.length).toBe(2);
|
||||
});
|
||||
|
||||
it('blocks on top of each other', async () => {
|
||||
const str = `block-beta
|
||||
columns 1
|
||||
block1["Block 1"]
|
||||
block2["Block 2"]
|
||||
`;
|
||||
|
||||
block.parse(str);
|
||||
|
||||
const blocks = db.getBlocks();
|
||||
expect(db.getColumns('root')).toBe(1);
|
||||
expect(blocks.length).toBe(2);
|
||||
});
|
||||
|
||||
it('compound blocks 2', async () => {
|
||||
const str = `block-beta
|
||||
block
|
||||
aBlock["ABlock"]
|
||||
bBlock["BBlock"]
|
||||
end
|
||||
`;
|
||||
|
||||
block.parse(str);
|
||||
const blocks = db.getBlocks();
|
||||
expect(blocks.length).toBe(1);
|
||||
|
||||
expect(blocks[0].children.length).toBe(2);
|
||||
expect(blocks[0].id).not.toBe(undefined);
|
||||
expect(blocks[0].label).toBe('');
|
||||
expect(blocks[0].type).toBe('composite');
|
||||
|
||||
const aBlock = blocks[0].children[0];
|
||||
|
||||
expect(aBlock.id).not.toBe(aBlock);
|
||||
expect(aBlock.label).toBe('ABlock');
|
||||
expect(aBlock.type).toBe('square');
|
||||
|
||||
const bBlock = blocks[0].children[1];
|
||||
expect(bBlock.id).not.toBe(bBlock);
|
||||
expect(bBlock.label).toBe('BBlock');
|
||||
expect(bBlock.type).toBe('square');
|
||||
});
|
||||
it('compound blocks of compound blocks', async () => {
|
||||
const str = `block-beta
|
||||
block
|
||||
aBlock["ABlock"]
|
||||
block
|
||||
bBlock["BBlock"]
|
||||
end
|
||||
end
|
||||
`;
|
||||
|
||||
block.parse(str);
|
||||
const blocks = db.getBlocks();
|
||||
|
||||
const aBlock = blocks[0].children[0];
|
||||
const secondComposite = blocks[0].children[1];
|
||||
const bBlock = blocks[0].children[1].children[0];
|
||||
|
||||
expect(blocks[0].children.length).toBe(2);
|
||||
expect(blocks[0].id).not.toBe(undefined);
|
||||
expect(blocks[0].label).toBe('');
|
||||
expect(blocks[0].type).toBe('composite');
|
||||
|
||||
expect(secondComposite.children.length).toBe(1);
|
||||
expect(secondComposite.id).not.toBe(undefined);
|
||||
expect(secondComposite.label).toBe('');
|
||||
expect(secondComposite.type).toBe('composite');
|
||||
|
||||
expect(aBlock.id).not.toBe(aBlock);
|
||||
expect(aBlock.label).toBe('ABlock');
|
||||
expect(aBlock.type).toBe('square');
|
||||
|
||||
expect(bBlock.id).not.toBe(bBlock);
|
||||
expect(bBlock.label).toBe('BBlock');
|
||||
expect(bBlock.type).toBe('square');
|
||||
});
|
||||
it('compound blocks with title', async () => {
|
||||
const str = `block-beta
|
||||
block:compoundBlock["Compound block"]
|
||||
columns 1
|
||||
block2["Block 2"]
|
||||
end
|
||||
`;
|
||||
|
||||
block.parse(str);
|
||||
|
||||
const blocks = db.getBlocks();
|
||||
expect(blocks.length).toBe(1);
|
||||
|
||||
const compoundBlock = blocks[0];
|
||||
const block2 = compoundBlock.children[0];
|
||||
|
||||
expect(compoundBlock.children.length).toBe(1);
|
||||
expect(compoundBlock.id).toBe('compoundBlock');
|
||||
expect(compoundBlock.label).toBe('Compound block');
|
||||
expect(compoundBlock.type).toBe('composite');
|
||||
|
||||
expect(block2.id).toBe('block2');
|
||||
expect(block2.label).toBe('Block 2');
|
||||
expect(block2.type).toBe('square');
|
||||
});
|
||||
it('blocks mixed with compound blocks', async () => {
|
||||
const str = `block-beta
|
||||
columns 1
|
||||
block1["Block 1"]
|
||||
|
||||
block
|
||||
columns 2
|
||||
block2["Block 2"]
|
||||
block3["Block 3"]
|
||||
end
|
||||
`;
|
||||
|
||||
block.parse(str);
|
||||
|
||||
const blocks = db.getBlocks();
|
||||
expect(blocks.length).toBe(2);
|
||||
|
||||
const compoundBlock = blocks[1];
|
||||
const block2 = compoundBlock.children[0];
|
||||
|
||||
expect(compoundBlock.children.length).toBe(2);
|
||||
|
||||
expect(block2.id).toBe('block2');
|
||||
expect(block2.label).toBe('Block 2');
|
||||
expect(block2.type).toBe('square');
|
||||
});
|
||||
|
||||
it('Arrow blocks', async () => {
|
||||
const str = `block-beta
|
||||
columns 3
|
||||
block1["Block 1"]
|
||||
blockArrow<[" "]>(right)
|
||||
block2["Block 2"]`;
|
||||
|
||||
block.parse(str);
|
||||
|
||||
const blocks = db.getBlocks();
|
||||
expect(blocks.length).toBe(3);
|
||||
|
||||
const block1 = blocks[0];
|
||||
const blockArrow = blocks[1];
|
||||
const block2 = blocks[2];
|
||||
|
||||
expect(block1.id).toBe('block1');
|
||||
expect(blockArrow.id).toBe('blockArrow');
|
||||
expect(block2.id).toBe('block2');
|
||||
expect(block2.label).toBe('Block 2');
|
||||
expect(block2.type).toBe('square');
|
||||
expect(blockArrow.type).toBe('block_arrow');
|
||||
expect(blockArrow.directions).toContain('right');
|
||||
});
|
||||
it('Arrow blocks with multiple points', async () => {
|
||||
const str = `block-beta
|
||||
columns 1
|
||||
A
|
||||
blockArrow<[" "]>(up, down)
|
||||
block
|
||||
columns 3
|
||||
B
|
||||
C
|
||||
D
|
||||
end`;
|
||||
|
||||
block.parse(str);
|
||||
|
||||
const blocks = db.getBlocks();
|
||||
expect(blocks.length).toBe(3);
|
||||
|
||||
const blockArrow = blocks[1];
|
||||
expect(blockArrow.type).toBe('block_arrow');
|
||||
expect(blockArrow.directions).toContain('up');
|
||||
expect(blockArrow.directions).toContain('down');
|
||||
expect(blockArrow.directions).not.toContain('right');
|
||||
});
|
||||
it('blocks with different widths', async () => {
|
||||
const str = `block-beta
|
||||
columns 3
|
||||
one["One Slot"]
|
||||
two["Two slots"]:2
|
||||
`;
|
||||
|
||||
block.parse(str);
|
||||
|
||||
const blocks = db.getBlocks();
|
||||
expect(blocks.length).toBe(2);
|
||||
const one = blocks[0];
|
||||
const two = blocks[1];
|
||||
expect(two.widthInColumns).toBe(2);
|
||||
});
|
||||
it('empty blocks', async () => {
|
||||
const str = `block-beta
|
||||
columns 3
|
||||
space
|
||||
middle["In the middle"]
|
||||
space
|
||||
`;
|
||||
|
||||
block.parse(str);
|
||||
|
||||
const blocks = db.getBlocks();
|
||||
expect(blocks.length).toBe(3);
|
||||
const sp1 = blocks[0];
|
||||
const middle = blocks[1];
|
||||
const sp2 = blocks[2];
|
||||
expect(sp1.type).toBe('space');
|
||||
expect(sp2.type).toBe('space');
|
||||
expect(middle.label).toBe('In the middle');
|
||||
});
|
||||
it('classDef statements applied to a block', async () => {
|
||||
const str = `block-beta
|
||||
classDef black color:#ffffff, fill:#000000;
|
||||
|
||||
mc["Memcache"]
|
||||
class mc black
|
||||
`;
|
||||
|
||||
block.parse(str);
|
||||
const blocks = db.getBlocks();
|
||||
expect(blocks.length).toBe(1);
|
||||
const mc = blocks[0];
|
||||
expect(mc.classes).toContain('black');
|
||||
const classes = db.getClasses();
|
||||
const black = classes.black;
|
||||
expect(black.id).toBe('black');
|
||||
expect(black.styles[0]).toEqual('color:#ffffff');
|
||||
});
|
||||
it('style statements applied to a block', async () => {
|
||||
const str = `block-beta
|
||||
columns 1
|
||||
B["A wide one in the middle"]
|
||||
style B fill:#f9F,stroke:#333,stroke-width:4px
|
||||
`;
|
||||
|
||||
block.parse(str);
|
||||
const blocks = db.getBlocks();
|
||||
expect(blocks.length).toBe(1);
|
||||
const B = blocks[0];
|
||||
expect(B.styles).toContain('fill:#f9F');
|
||||
});
|
||||
});
|
||||
});
|
261
packages/mermaid/src/diagrams/block/renderHelpers.ts
Normal file
261
packages/mermaid/src/diagrams/block/renderHelpers.ts
Normal file
@ -0,0 +1,261 @@
|
||||
import { getStylesFromArray } from '../../utils.js';
|
||||
import { insertNode, positionNode } from '../../dagre-wrapper/nodes.js';
|
||||
import { insertEdge, insertEdgeLabel, positionEdgeLabel } from '../../dagre-wrapper/edges.js';
|
||||
import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
|
||||
import { getConfig } from '../../config.js';
|
||||
import type { ContainerElement } from 'd3';
|
||||
import type { Block } from './blockTypes.js';
|
||||
import type { BlockDB } from './blockDB.js';
|
||||
|
||||
interface Node {
|
||||
classes: string;
|
||||
}
|
||||
|
||||
function getNodeFromBlock(block: Block, db: BlockDB, positioned = false) {
|
||||
const vertex = block;
|
||||
|
||||
let classStr = 'default';
|
||||
if ((vertex?.classes?.length || 0) > 0) {
|
||||
classStr = (vertex?.classes || []).join(' ');
|
||||
}
|
||||
classStr = classStr + ' flowchart-label';
|
||||
|
||||
// We create a SVG label, either by delegating to addHtmlLabel or manually
|
||||
let radius = 0;
|
||||
let shape = '';
|
||||
let layoutOptions = {};
|
||||
let padding;
|
||||
// Set the shape based parameters
|
||||
switch (vertex.type) {
|
||||
case 'round':
|
||||
radius = 5;
|
||||
shape = 'rect';
|
||||
break;
|
||||
case 'composite':
|
||||
radius = 0;
|
||||
shape = 'composite';
|
||||
padding = 0;
|
||||
break;
|
||||
case 'square':
|
||||
shape = 'rect';
|
||||
break;
|
||||
case 'diamond':
|
||||
shape = 'question';
|
||||
layoutOptions = {
|
||||
portConstraints: 'FIXED_SIDE',
|
||||
};
|
||||
break;
|
||||
case 'hexagon':
|
||||
shape = 'hexagon';
|
||||
break;
|
||||
case 'block_arrow':
|
||||
shape = 'block_arrow';
|
||||
break;
|
||||
case 'odd':
|
||||
shape = 'rect_left_inv_arrow';
|
||||
break;
|
||||
case 'lean_right':
|
||||
shape = 'lean_right';
|
||||
break;
|
||||
case 'lean_left':
|
||||
shape = 'lean_left';
|
||||
break;
|
||||
case 'trapezoid':
|
||||
shape = 'trapezoid';
|
||||
break;
|
||||
case 'inv_trapezoid':
|
||||
shape = 'inv_trapezoid';
|
||||
break;
|
||||
case 'rect_left_inv_arrow':
|
||||
shape = 'rect_left_inv_arrow';
|
||||
break;
|
||||
case 'circle':
|
||||
shape = 'circle';
|
||||
break;
|
||||
case 'ellipse':
|
||||
shape = 'ellipse';
|
||||
break;
|
||||
case 'stadium':
|
||||
shape = 'stadium';
|
||||
break;
|
||||
case 'subroutine':
|
||||
shape = 'subroutine';
|
||||
break;
|
||||
case 'cylinder':
|
||||
shape = 'cylinder';
|
||||
break;
|
||||
case 'group':
|
||||
shape = 'rect';
|
||||
break;
|
||||
case 'doublecircle':
|
||||
shape = 'doublecircle';
|
||||
break;
|
||||
default:
|
||||
shape = 'rect';
|
||||
}
|
||||
|
||||
const styles = getStylesFromArray(vertex?.styles || []);
|
||||
|
||||
// Use vertex id as text in the box if no text is provided by the graph definition
|
||||
const vertexText = vertex.label;
|
||||
|
||||
const bounds = vertex.size || { width: 0, height: 0, x: 0, y: 0 };
|
||||
// Add the node
|
||||
const node = {
|
||||
labelStyle: styles.labelStyle,
|
||||
shape: shape,
|
||||
labelText: vertexText,
|
||||
rx: radius,
|
||||
ry: radius,
|
||||
class: classStr,
|
||||
style: styles.style,
|
||||
id: vertex.id,
|
||||
directions: vertex.directions,
|
||||
width: bounds.width,
|
||||
height: bounds.height,
|
||||
x: bounds.x,
|
||||
y: bounds.y,
|
||||
positioned,
|
||||
intersect: undefined,
|
||||
type: vertex.type,
|
||||
padding: padding ?? (getConfig()?.block?.padding || 0),
|
||||
};
|
||||
return node;
|
||||
}
|
||||
async function calculateBlockSize(
|
||||
elem: d3.Selection<SVGGElement, unknown, HTMLElement, any>,
|
||||
block: any,
|
||||
db: any
|
||||
) {
|
||||
const node = getNodeFromBlock(block, db, false);
|
||||
if (node.type === 'group') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the element to the DOM to size it
|
||||
const nodeEl = await insertNode(elem, node);
|
||||
const boundingBox = nodeEl.node().getBBox();
|
||||
const obj = db.getBlock(node.id);
|
||||
obj.size = { width: boundingBox.width, height: boundingBox.height, x: 0, y: 0, node: nodeEl };
|
||||
db.setBlock(obj);
|
||||
nodeEl.remove();
|
||||
}
|
||||
type ActionFun = typeof calculateBlockSize;
|
||||
|
||||
export async function insertBlockPositioned(elem: any, block: Block, db: any) {
|
||||
const node = getNodeFromBlock(block, db, true);
|
||||
// Add the element to the DOM to size it
|
||||
const obj = db.getBlock(node.id);
|
||||
if (obj.type !== 'space') {
|
||||
const nodeEl = await insertNode(elem, node);
|
||||
block.intersect = node?.intersect;
|
||||
positionNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
export async function performOperations(
|
||||
elem: d3.Selection<SVGGElement, unknown, HTMLElement, any>,
|
||||
blocks: Block[],
|
||||
db: BlockDB,
|
||||
operation: ActionFun
|
||||
) {
|
||||
for (const block of blocks) {
|
||||
await operation(elem, block, db);
|
||||
if (block.children) {
|
||||
await performOperations(elem, block.children, db, operation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function calculateBlockSizes(elem: any, blocks: Block[], db: BlockDB) {
|
||||
await performOperations(elem, blocks, db, calculateBlockSize);
|
||||
}
|
||||
|
||||
export async function insertBlocks(
|
||||
elem: d3.Selection<SVGGElement, unknown, HTMLElement, any>,
|
||||
blocks: Block[],
|
||||
db: BlockDB
|
||||
) {
|
||||
await performOperations(elem, blocks, db, insertBlockPositioned);
|
||||
}
|
||||
|
||||
export async function insertEdges(
|
||||
elem: any,
|
||||
edges: Block[],
|
||||
blocks: Block[],
|
||||
db: BlockDB,
|
||||
id: string
|
||||
) {
|
||||
const g = new graphlib.Graph({
|
||||
multigraph: true,
|
||||
compound: true,
|
||||
});
|
||||
g.setGraph({
|
||||
rankdir: 'TB',
|
||||
nodesep: 10,
|
||||
ranksep: 10,
|
||||
marginx: 8,
|
||||
marginy: 8,
|
||||
});
|
||||
|
||||
for (const block of blocks) {
|
||||
if (block.size) {
|
||||
g.setNode(block.id, {
|
||||
width: block.size.width,
|
||||
height: block.size.height,
|
||||
intersect: block.intersect,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (const edge of edges) {
|
||||
// elem, e, edge, clusterDb, diagramType, graph;
|
||||
if (edge.start && edge.end) {
|
||||
const startBlock = db.getBlock(edge.start);
|
||||
const endBlock = db.getBlock(edge.end);
|
||||
|
||||
if (startBlock?.size && endBlock?.size) {
|
||||
const start = startBlock.size;
|
||||
const end = endBlock.size;
|
||||
const points = [
|
||||
{ x: start.x, y: start.y },
|
||||
{ x: start.x + (end.x - start.x) / 2, y: start.y + (end.y - start.y) / 2 },
|
||||
{ x: end.x, y: end.y },
|
||||
];
|
||||
// edge.points = points;
|
||||
await insertEdge(
|
||||
elem,
|
||||
{ v: edge.start, w: edge.end, name: edge.id },
|
||||
{
|
||||
...edge,
|
||||
arrowTypeEnd: edge.arrowTypeEnd,
|
||||
arrowTypeStart: edge.arrowTypeStart,
|
||||
points,
|
||||
classes: 'edge-thickness-normal edge-pattern-solid flowchart-link LS-a1 LE-b1',
|
||||
},
|
||||
undefined,
|
||||
'block',
|
||||
g,
|
||||
id
|
||||
);
|
||||
if (edge.label) {
|
||||
await insertEdgeLabel(elem, {
|
||||
...edge,
|
||||
label: edge.label,
|
||||
labelStyle: 'stroke: #333; stroke-width: 1.5px;fill:none;',
|
||||
arrowTypeEnd: edge.arrowTypeEnd,
|
||||
arrowTypeStart: edge.arrowTypeStart,
|
||||
points,
|
||||
classes: 'edge-thickness-normal edge-pattern-solid flowchart-link LS-a1 LE-b1',
|
||||
});
|
||||
await positionEdgeLabel(
|
||||
{ ...edge, x: points[1].x, y: points[1].y },
|
||||
{
|
||||
originalPath: points,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
147
packages/mermaid/src/diagrams/block/styles.ts
Normal file
147
packages/mermaid/src/diagrams/block/styles.ts
Normal file
@ -0,0 +1,147 @@
|
||||
import * as khroma from 'khroma';
|
||||
|
||||
/** Returns the styles given options */
|
||||
export interface BlockChartStyleOptions {
|
||||
arrowheadColor: string;
|
||||
border2: string;
|
||||
clusterBkg: string;
|
||||
clusterBorder: string;
|
||||
edgeLabelBackground: string;
|
||||
fontFamily: string;
|
||||
lineColor: string;
|
||||
mainBkg: string;
|
||||
nodeBorder: string;
|
||||
nodeTextColor: string;
|
||||
tertiaryColor: string;
|
||||
textColor: string;
|
||||
titleColor: string;
|
||||
}
|
||||
|
||||
const fade = (color: string, opacity: number) => {
|
||||
// @ts-ignore TODO: incorrect types from khroma
|
||||
const channel = khroma.channel;
|
||||
|
||||
const r = channel(color, 'r');
|
||||
const g = channel(color, 'g');
|
||||
const b = channel(color, 'b');
|
||||
|
||||
// @ts-ignore incorrect types from khroma
|
||||
return khroma.rgba(r, g, b, opacity);
|
||||
};
|
||||
|
||||
const getStyles = (options: BlockChartStyleOptions) =>
|
||||
`.label {
|
||||
font-family: ${options.fontFamily};
|
||||
color: ${options.nodeTextColor || options.textColor};
|
||||
}
|
||||
.cluster-label text {
|
||||
fill: ${options.titleColor};
|
||||
}
|
||||
.cluster-label span,p {
|
||||
color: ${options.titleColor};
|
||||
}
|
||||
|
||||
|
||||
|
||||
.label text,span,p {
|
||||
fill: ${options.nodeTextColor || options.textColor};
|
||||
color: ${options.nodeTextColor || options.textColor};
|
||||
}
|
||||
|
||||
.node rect,
|
||||
.node circle,
|
||||
.node ellipse,
|
||||
.node polygon,
|
||||
.node path {
|
||||
fill: ${options.mainBkg};
|
||||
stroke: ${options.nodeBorder};
|
||||
stroke-width: 1px;
|
||||
}
|
||||
.flowchart-label text {
|
||||
text-anchor: middle;
|
||||
}
|
||||
// .flowchart-label .text-outer-tspan {
|
||||
// text-anchor: middle;
|
||||
// }
|
||||
// .flowchart-label .text-inner-tspan {
|
||||
// text-anchor: start;
|
||||
// }
|
||||
|
||||
.node .label {
|
||||
text-align: center;
|
||||
}
|
||||
.node.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.arrowheadPath {
|
||||
fill: ${options.arrowheadColor};
|
||||
}
|
||||
|
||||
.edgePath .path {
|
||||
stroke: ${options.lineColor};
|
||||
stroke-width: 2.0px;
|
||||
}
|
||||
|
||||
.flowchart-link {
|
||||
stroke: ${options.lineColor};
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.edgeLabel {
|
||||
background-color: ${options.edgeLabelBackground};
|
||||
rect {
|
||||
opacity: 0.5;
|
||||
background-color: ${options.edgeLabelBackground};
|
||||
fill: ${options.edgeLabelBackground};
|
||||
}
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* For html labels only */
|
||||
.labelBkg {
|
||||
background-color: ${fade(options.edgeLabelBackground, 0.5)};
|
||||
// background-color:
|
||||
}
|
||||
|
||||
.node .cluster {
|
||||
// fill: ${fade(options.mainBkg, 0.5)};
|
||||
fill: ${fade(options.clusterBkg, 0.5)};
|
||||
stroke: ${fade(options.clusterBorder, 0.2)};
|
||||
box-shadow: rgba(50, 50, 93, 0.25) 0px 13px 27px -5px, rgba(0, 0, 0, 0.3) 0px 8px 16px -8px;
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.cluster text {
|
||||
fill: ${options.titleColor};
|
||||
}
|
||||
|
||||
.cluster span,p {
|
||||
color: ${options.titleColor};
|
||||
}
|
||||
/* .cluster div {
|
||||
color: ${options.titleColor};
|
||||
} */
|
||||
|
||||
div.mermaidTooltip {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
max-width: 200px;
|
||||
padding: 2px;
|
||||
font-family: ${options.fontFamily};
|
||||
font-size: 12px;
|
||||
background: ${options.tertiaryColor};
|
||||
border: 1px solid ${options.border2};
|
||||
border-radius: 2px;
|
||||
pointer-events: none;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.flowchartTitleText {
|
||||
text-anchor: middle;
|
||||
font-size: 18px;
|
||||
fill: ${options.textColor};
|
||||
}
|
||||
`;
|
||||
|
||||
export default getStyles;
|
@ -11,7 +11,7 @@ let c4ShapeArray = [];
|
||||
let boundaryParseStack = [''];
|
||||
let currentBoundaryParse = 'global';
|
||||
let parentBoundaryParse = '';
|
||||
let boundarys = [
|
||||
let boundaries = [
|
||||
{
|
||||
alias: 'global',
|
||||
label: { text: 'global' },
|
||||
@ -312,12 +312,12 @@ export const addPersonOrSystemBoundary = function (alias, label, type, tags, lin
|
||||
}
|
||||
|
||||
let boundary = {};
|
||||
const old = boundarys.find((boundary) => boundary.alias === alias);
|
||||
const old = boundaries.find((boundary) => boundary.alias === alias);
|
||||
if (old && alias === old.alias) {
|
||||
boundary = old;
|
||||
} else {
|
||||
boundary.alias = alias;
|
||||
boundarys.push(boundary);
|
||||
boundaries.push(boundary);
|
||||
}
|
||||
|
||||
// Don't allow null labels, either
|
||||
@ -368,12 +368,12 @@ export const addContainerBoundary = function (alias, label, type, tags, link) {
|
||||
}
|
||||
|
||||
let boundary = {};
|
||||
const old = boundarys.find((boundary) => boundary.alias === alias);
|
||||
const old = boundaries.find((boundary) => boundary.alias === alias);
|
||||
if (old && alias === old.alias) {
|
||||
boundary = old;
|
||||
} else {
|
||||
boundary.alias = alias;
|
||||
boundarys.push(boundary);
|
||||
boundaries.push(boundary);
|
||||
}
|
||||
|
||||
// Don't allow null labels, either
|
||||
@ -433,12 +433,12 @@ export const addDeploymentNode = function (
|
||||
}
|
||||
|
||||
let boundary = {};
|
||||
const old = boundarys.find((boundary) => boundary.alias === alias);
|
||||
const old = boundaries.find((boundary) => boundary.alias === alias);
|
||||
if (old && alias === old.alias) {
|
||||
boundary = old;
|
||||
} else {
|
||||
boundary.alias = alias;
|
||||
boundarys.push(boundary);
|
||||
boundaries.push(boundary);
|
||||
}
|
||||
|
||||
// Don't allow null labels, either
|
||||
@ -514,7 +514,7 @@ export const updateElStyle = function (
|
||||
) {
|
||||
let old = c4ShapeArray.find((element) => element.alias === elementName);
|
||||
if (old === undefined) {
|
||||
old = boundarys.find((element) => element.alias === elementName);
|
||||
old = boundaries.find((element) => element.alias === elementName);
|
||||
if (old === undefined) {
|
||||
return;
|
||||
}
|
||||
@ -697,14 +697,19 @@ export const getC4ShapeKeys = function (parentBoundary) {
|
||||
return Object.keys(getC4ShapeArray(parentBoundary));
|
||||
};
|
||||
|
||||
export const getBoundarys = function (parentBoundary) {
|
||||
export const getBoundaries = function (parentBoundary) {
|
||||
if (parentBoundary === undefined || parentBoundary === null) {
|
||||
return boundarys;
|
||||
return boundaries;
|
||||
} else {
|
||||
return boundarys.filter((boundary) => boundary.parentBoundary === parentBoundary);
|
||||
return boundaries.filter((boundary) => boundary.parentBoundary === parentBoundary);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link getBoundaries} instead
|
||||
*/
|
||||
export const getBoundarys = getBoundaries;
|
||||
|
||||
export const getRels = function () {
|
||||
return rels;
|
||||
};
|
||||
@ -723,7 +728,7 @@ export const autoWrap = function () {
|
||||
|
||||
export const clear = function () {
|
||||
c4ShapeArray = [];
|
||||
boundarys = [
|
||||
boundaries = [
|
||||
{
|
||||
alias: 'global',
|
||||
label: { text: 'global' },
|
||||
@ -804,6 +809,7 @@ export default {
|
||||
getC4ShapeArray,
|
||||
getC4Shape,
|
||||
getC4ShapeKeys,
|
||||
getBoundaries,
|
||||
getBoundarys,
|
||||
getCurrentBoundaryParse,
|
||||
getParentBoundaryParse,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user