Merge branch 'develop' into next

* develop: (99 commits)
  Fix spelling
  Fix community integrations
  Fix docs
  docs: Fix config
  Update all minor dependencies
  Amend docs to document gitgraph parallel commits
  Fix lint
  Use Yarn Add COREPACK_ENABLE_STRICT
  Added link to Blazorade Mermaid to the community integrations page.
  Bump node version
  Add lcov to cspell
  Correcting path to docker-entrypoint.sh
  Update recommended Vitest extension
  Replace mermaid-js.github.io links
  Replace links to docs with links to webhelp
  Link to contributing page on webhelp
  Changes to timeline.md 1. Added colons to all 'NOTES' for consistency.
  Changes to timeline.md 1. Updates the Wikipedia citation to include a link. 2. Removed periods from documentation sections to be consistent (some had periods, some didn't) 3. Added a space to a coding example for spacing consistency.
  Replace version number placeholder
  Fix link to Contributors section in README
  ...
This commit is contained in:
Sidharth Vinod 2024-03-01 12:18:25 +05:30
commit 5807d521b7
No known key found for this signature in database
GPG Key ID: FB5CCD378D3907CD
133 changed files with 5425 additions and 3205 deletions

140
.cspell/code-terms.txt Normal file
View File

@ -0,0 +1,140 @@
# 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
iife
interp
introdcued
INVTRAPEND
INVTRAPSTART
JDBC
jison
Kaufmann
keyify
LABELPOS
LABELTYPE
lcov
LEFTOF
Lexa
linebreak
LINETYPE
LINKSTYLE
LLABEL
loglevel
LOGMSG
lookaheads
mdast
metafile
minlen
Mstartx
MULT
NODIR
NSTR
outdir
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
View File

@ -0,0 +1,8 @@
# Contributors to mermaidjs, one per line
Ashish Jain
cpettitt
Dong Cai
Nikolay Rozhkov
Peng Xiao
subhash-halder
Vinod Sidharth

View 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

71
.cspell/libraries.txt Normal file
View File

@ -0,0 +1,71 @@
# 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
langium
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
View 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
View File

@ -0,0 +1 @@
newbranch

View File

@ -78,9 +78,9 @@ module.exports = {
'@cspell/spellchecker': [
'error',
{
checkIdentifiers: false,
checkStrings: false,
checkStringTemplates: false,
checkIdentifiers: true,
checkStrings: true,
checkStringTemplates: true,
},
],
'no-empty': [
@ -159,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: {

5
.github/lychee.toml vendored
View File

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

View File

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

View File

@ -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'],
};

View File

@ -1 +1 @@
v20.11.0
v20.11.1

View File

@ -2,7 +2,7 @@
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"zixuanchen.vitest-explorer",
"vitest.explorer",
"luniclynx.bison"
]
}

View File

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

View File

@ -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) 中找到。
## 安全

View File

@ -1,214 +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",
"colours",
"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",
"iife",
"inkdrop",
"jaoude",
"jgreywolf",
"jison",
"jiti",
"kaufmann",
"khroma",
"klemm",
"klink",
"knsv",
"knut",
"knutsveidqvist",
"laganeckas",
"langium",
"linetype",
"lintstagedrc",
"logmsg",
"lucida",
"markdownish",
"matthieu",
"matthieumorel",
"mdast",
"mdbook",
"mermaidjs",
"mermerd",
"metafile",
"mindaugas",
"mindmap",
"mindmaps",
"mitigations",
"mkdocs",
"mmorel",
"mult",
"neurodiverse",
"nextra",
"nikolay",
"nirname",
"npmjs",
"orlandoni",
"outdir",
"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
View 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

View File

@ -92,6 +92,31 @@ describe('Gantt diagram', () => {
{}
);
});
it('should handle multiple dependencies syntax with after and until', () => {
imgSnapshotTest(
`
gantt
dateFormat YYYY-MM-DD
axisFormat %d/%m
title Adding GANTT diagram to mermaid
excludes weekdays 2014-01-10
todayMarker off
section team's critical event
deadline A :milestone, crit, deadlineA, 2024-02-01, 0
deadline B :milestone, crit, deadlineB, 2024-02-15, 0
boss on leave :bossaway, 2024-01-28, 2024-02-11
section new intern
onboarding :onboarding, 2024-01-02, 1w
literature review :litreview, 2024-01-02, 10d
project A :projectA, after onboarding litreview, until deadlineA bossaway
chilling :chilling, after projectA, until deadlineA
project B :projectB, after deadlineA, until deadlineB
`,
{}
);
});
it('should FAIL redering a gantt chart for issue #1060 with invalid date', () => {
imgSnapshotTest(
`

View File

@ -943,4 +943,74 @@ gitGraph TB:
{ gitGraph: { parallelCommits: true } }
);
});
it('46: should render GitGraph with merge back and merge forward', () => {
imgSnapshotTest(
`gitGraph LR:
commit
branch branch-A
branch branch-B
commit
checkout branch-A
merge branch-B
checkout branch-B
merge branch-A
`,
{ gitGraph: { parallelCommits: true } }
);
});
it('47: should render GitGraph with merge back and merge forward | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph TB:
commit
branch branch-A
branch branch-B
commit
checkout branch-A
merge branch-B
checkout branch-B
merge branch-A
`,
{ gitGraph: { parallelCommits: true } }
);
});
it('48: should render GitGraph with merge on a new branch | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph LR:
commit
branch branch-B order: 2
commit
branch branch-A
merge main
checkout branch-B
merge branch-A
`,
{ gitGraph: { parallelCommits: true } }
);
});
it('49: should render GitGraph with merge on a new branch | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph TB:
commit
branch branch-B order: 2
commit
branch branch-A
merge main
checkout branch-B
merge branch-A
`,
{ gitGraph: { parallelCommits: true } }
);
});
});

View 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' }
// );
// });
});

View File

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

View File

@ -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&nbsp; $$\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({

View File

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

View File

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

View File

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

View File

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

View File

@ -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
View 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>
```

View File

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

View File

@ -393,3 +393,8 @@ mermaid.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
--->

View File

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

View File

@ -80,3 +80,5 @@ graph LR;
**Output**
![Example graph of the Python integration](img/python-mermaid-integration.png)
<!--- cspell:ignore Elle Jaoude Neurodiverse graphbytes --->

View File

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

View File

@ -425,7 +425,7 @@ block-beta
ida space:3 idb idc
```
Note that you can set how many columns the spece block occupied using the number notaion `space:num` where num is a number indicating the num columns width. You can alsio use `space` which defaults to one column.
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.
@ -640,7 +640,7 @@ A common mistake is incorrect linking syntax, which can lead to unexpected resul
A - B
**Correction**:
Ensure that links between blocks are correctly specified with arrows (--> or ---) to define the direction and type of connection. Also rememeber 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:
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

View File

@ -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.
@ -621,3 +621,5 @@ UpdateRelStyle(customerA, bankA, $offsetY="60")
UpdateRelStyle(db, db2, $offsetY="-10")
```
<!--- cspell:ignore bigbank bigbankdb techn mbsfacade --->

View File

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

View File

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

View File

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

View File

@ -1200,3 +1200,5 @@ mermaid.flowchartConfig = {
width: 100%
}
```
<!--- cspell:ignore lagom --->

View File

@ -67,8 +67,8 @@ gantt
Create tests for parser :crit, active, 3d
Future task in critical line :crit, 5d
Create tests for renderer :2d
Add to mermaid :1d
Functionality added :milestone, 2014-01-25, 0d
Add to mermaid :until isadded
Functionality added :milestone, isadded, 2014-01-25, 0d
section Documentation
Describe gantt syntax :active, a1, after des1, 3d
@ -100,8 +100,8 @@ gantt
Create tests for parser :crit, active, 3d
Future task in critical line :crit, 5d
Create tests for renderer :2d
Add to mermaid :1d
Functionality added :milestone, 2014-01-25, 0d
Add to mermaid :until isadded
Functionality added :milestone, isadded, 2014-01-25, 0d
section Documentation
Describe gantt syntax :active, a1, after des1, 3d
@ -124,18 +124,26 @@ After processing the tags, the remaining metadata items are interpreted as follo
2. If two items are specified, the last item is interpreted as in the previous case. The first item can either specify an explicit start date/time (in the format specified by `dateFormat`) or reference another task using `after <otherTaskID> [[otherTaskID2 [otherTaskID3]]...]`. In the latter case, the start date of the task will be set according to the latest end date of any referenced task.
3. If three items are specified, the last two will be interpreted as in the previous case. The first item will denote the ID of the task, which can be referenced using the `later <taskID>` syntax.
| Metadata syntax | Start date | End date | ID |
| ------------------------------------------ | --------------------------------------------------- | ------------------------------------------- | -------- |
| `<taskID>, <startDate>, <endDate>` | `startdate` as interpreted using `dateformat` | `endDate` as interpreted using `dateformat` | `taskID` |
| `<taskID>, <startDate>, <length>` | `startdate` as interpreted using `dateformat` | Start date + `length` | `taskID` |
| `<taskID>, after <otherTaskId>, <endDate>` | End date of previously specified task `otherTaskID` | `endDate` as interpreted using `dateformat` | `taskID` |
| `<taskID>, after <otherTaskId>, <length>` | End date of previously specified task `otherTaskID` | Start date + `length` | `taskID` |
| `<startDate>, <endDate>` | `startdate` as interpreted using `dateformat` | `enddate` as interpreted using `dateformat` | n/a |
| `<startDate>, <length>` | `startdate` as interpreted using `dateformat` | Start date + `length` | n/a |
| `after <otherTaskID>, <endDate>` | End date of previously specified task `otherTaskID` | `enddate` as interpreted using `dateformat` | n/a |
| `after <otherTaskID>, <length>` | End date of previously specified task `otherTaskID` | Start date + `length` | n/a |
| `<endDate>` | End date of preceding task | `enddate` as interpreted using `dateformat` | n/a |
| `<length>` | End date of preceding task | Start date + `length` | n/a |
| Metadata syntax | Start date | End date | ID |
| ---------------------------------------------------- | --------------------------------------------------- | ----------------------------------------------------- | -------- |
| `<taskID>, <startDate>, <endDate>` | `startdate` as interpreted using `dateformat` | `endDate` as interpreted using `dateformat` | `taskID` |
| `<taskID>, <startDate>, <length>` | `startdate` as interpreted using `dateformat` | Start date + `length` | `taskID` |
| `<taskID>, after <otherTaskId>, <endDate>` | End date of previously specified task `otherTaskID` | `endDate` as interpreted using `dateformat` | `taskID` |
| `<taskID>, after <otherTaskId>, <length>` | End date of previously specified task `otherTaskID` | Start date + `length` | `taskID` |
| `<taskID>, <startDate>, until <otherTaskId>` | `startdate` as interpreted using `dateformat` | Start date of previously specified task `otherTaskID` | `taskID` |
| `<taskID>, after <otherTaskId>, until <otherTaskId>` | End date of previously specified task `otherTaskID` | Start date of previously specified task `otherTaskID` | `taskID` |
| `<startDate>, <endDate>` | `startdate` as interpreted using `dateformat` | `enddate` as interpreted using `dateformat` | n/a |
| `<startDate>, <length>` | `startdate` as interpreted using `dateformat` | Start date + `length` | n/a |
| `after <otherTaskID>, <endDate>` | End date of previously specified task `otherTaskID` | `enddate` as interpreted using `dateformat` | n/a |
| `after <otherTaskID>, <length>` | End date of previously specified task `otherTaskID` | Start date + `length` | n/a |
| `<startDate>, until <otherTaskId>` | `startdate` as interpreted using `dateformat` | Start date of previously specified task `otherTaskID` | n/a |
| `after <otherTaskId>, until <otherTaskId>` | End date of previously specified task `otherTaskID` | Start date of previously specified task `otherTaskID` | n/a |
| `<endDate>` | End date of preceding task | `enddate` as interpreted using `dateformat` | n/a |
| `<length>` | End date of preceding task | Start date + `length` | n/a |
| `until <otherTaskId>` | End date of preceding task | Start date of previously specified task `otherTaskID` | n/a |
> **Note**
> Support for keyword `until` was added in (v\<MERMAID_RELEASE_VERSION>+). This can be used to define a task which is running until some other specific task or milestone starts.
For simplicity, the table does not show the use of multiple tasks listed with the `after` keyword. Here is an example of how to use it and how it's interpreted:
@ -144,6 +152,7 @@ gantt
apple :a, 2017-07-20, 1w
banana :crit, b, 2017-07-23, 1d
cherry :active, c, after b a, 1d
kiwi :d, 2017-07-20, until b c
```
```mermaid
@ -151,6 +160,7 @@ gantt
apple :a, 2017-07-20, 1w
banana :crit, b, 2017-07-23, 1d
cherry :active, c, after b a, 1d
kiwi :d, 2017-07-20, until b c
```
### Title
@ -294,11 +304,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
---
@ -549,3 +559,5 @@ gantt
section Issue1300
5 : 0, 5
```
<!--- cspell:ignore isadded --->

View File

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

View File

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

View File

@ -104,7 +104,7 @@ Please refer to the [configuration](/config/schema-docs/config-defs-packet-diagr
<!--
Theme variables are not currently working due to a mermaid bug. The passed values are not being propogated into styles function.
Theme variables are not currently working due to a mermaid bug. The passed values are not being propagated into styles function.
## Theme Variables

View File

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

View File

@ -301,3 +301,5 @@ Graph layout can be changed by setting `nodeAlignment` to:
- `center`
- `left`
- `right`
<!--- cspell:ignore Ngas bioenergy biofuel --->

View File

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

View File

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

View File

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

View File

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

View File

@ -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",
@ -86,6 +86,7 @@
"chokidar": "^3.5.3",
"concurrently": "^8.0.1",
"cors": "^2.8.5",
"cspell": "^8.3.2",
"cypress": "^12.17.4",
"cypress-image-snapshot": "^4.0.1",
"esbuild": "^0.20.0",

View File

@ -93,13 +93,13 @@ export const addVertices = async function (vert, svgId, root, doc, diagObj, pare
},
];
let radious = 0;
let radius = 0;
let _shape = '';
let layoutOptions = {};
// Set the shape based parameters
switch (vertex.type) {
case 'round':
radious = 5;
radius = 5;
_shape = 'rect';
break;
case 'square':
@ -163,8 +163,8 @@ export const addVertices = async function (vert, svgId, root, doc, diagObj, pare
shape: _shape,
labelText: vertexText,
labelType: vertex.labelType,
rx: radious,
ry: radious,
rx: radius,
ry: radius,
class: classStr,
style: styles.style,
id: vertex.id,

View File

@ -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",
@ -68,6 +68,8 @@
"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",
@ -86,6 +88,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",
@ -97,7 +100,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",

View File

@ -112,6 +112,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.

View File

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

View File

@ -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})`
);
}

View File

@ -60,7 +60,7 @@ const createLabel = (_vertexText, style, isTitle, isNode) => {
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:'),

View File

@ -269,7 +269,7 @@ export const intersection = (node, outsidePoint, insidePoint) => {
res.y = outsidePoint.y;
}
log.debug(`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,20 +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.debug('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) => {
// 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);
const inter = intersection(boundaryNode, lastPointOutside, point);
// // Check case where the intersection is the same as the last point
let pointPresent = false;

View File

@ -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);
@ -57,7 +57,7 @@ const recursiveRender = async (_elem, graph, diagramtype, id, parentCluster, sit
const o = await recursiveRender(
nodes,
node.graph,
diagramtype,
diagramType,
id,
graph.node(v),
siteConfig
@ -95,7 +95,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);
});
@ -147,7 +147,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);
});
@ -161,8 +161,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();
@ -173,7 +173,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 = {};

View File

@ -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);
// }
// });

View File

@ -240,8 +240,8 @@ const setHierarchy = (block: Block[]): void => {
blocks = rootBlock.children;
};
const getColumns = (blockid: string): number => {
const block = blockDatabase[blockid];
const getColumns = (blockId: string): number => {
const block = blockDatabase[blockId];
if (!block) {
return -1;
}

View File

@ -22,11 +22,11 @@ export function calculateBlockPosition(columns: number, position: number): Block
}
if (columns < 0) {
// Auto coulumns is set
// Auto columns is set
return { px: position, py: 0 };
}
if (columns === 1) {
// Auto coulumns is set
// Auto columns is set
return { px: 0, py: position };
}
// Calculate posX and posY
@ -122,7 +122,10 @@ function setBlockSizes(block: Block, db: BlockDB, siblingWidth = 0, siblingHeigh
}
const columns = block.columns || -1;
const numItems = block.children.length;
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;
@ -145,9 +148,10 @@ function setBlockSizes(block: Block, db: BlockDB, siblingWidth = 0, siblingHeigh
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, 'paddiong', padding);
log.debug('Size indata abc88 xSize', xSize, 'padding', padding);
// set width of block to max width of children
for (const child of block.children) {
@ -238,6 +242,7 @@ function layoutBlocks(block: Block, db: BlockDB) {
const halfWidth = width / 2;
child.size.x = startingPosX + padding + halfWidth;
// cspell:ignore pyid
log.debug(
`abc91 layout blocks (calc) px, pyid:${
child.id

View File

@ -173,13 +173,13 @@ spaceLines
| spaceLines NL
;
seperator
separator
: NL
{yy.getLogger().debug('Rule: seperator (NL) ');}
{yy.getLogger().debug('Rule: separator (NL) ');}
| SPACE
{yy.getLogger().debug('Rule: seperator (Space) ');}
{yy.getLogger().debug('Rule: separator (Space) ');}
| EOF
{yy.getLogger().debug('Rule: seperator (EOF) ');}
{yy.getLogger().debug('Rule: separator (EOF) ');}
;
start: BLOCK_DIAGRAM_KEY document EOF
@ -245,10 +245,10 @@ blockStatement
node
: NODE_ID
{ yy.getLogger().debug("Rule: node (NODE_ID seperator): ", $1); $$ = { id: $1 }; }
{ yy.getLogger().debug("Rule: node (NODE_ID separator): ", $1); $$ = { id: $1 }; }
| NODE_ID nodeShapeNLabel
{
yy.getLogger().debug("Rule: node (NODE_ID nodeShapeNLabel seperator): ", $1, $2);
yy.getLogger().debug("Rule: node (NODE_ID nodeShapeNLabel separator): ", $1, $2);
$$ = { id: $1, label: $2.label, typeStr: $2.typeStr, directions: $2.directions };
}
;

View File

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

View File

@ -542,15 +542,15 @@ function drawInsideBoundary(
);
}
parentBoundaryAlias = currentBoundary.alias;
let nextCurrentBoundarys = diagObj.db.getBoundarys(parentBoundaryAlias);
let nextCurrentBoundaries = diagObj.db.getBoundarys(parentBoundaryAlias);
if (nextCurrentBoundarys.length > 0) {
if (nextCurrentBoundaries.length > 0) {
// draw boundary inside currentBoundary
drawInsideBoundary(
diagram,
parentBoundaryAlias,
currentBounds,
nextCurrentBoundarys,
nextCurrentBoundaries,
diagObj
);
}

View File

@ -687,3 +687,5 @@ export default {
insertComputerIcon,
insertClockIcon,
};
// cspell:ignoreRegExp /'Mstartx.*/g

View File

@ -193,6 +193,7 @@ export const draw = function (text, id, _version, diagObj) {
const relations = diagObj.db.getRelations();
relations.forEach(function (relation) {
log.info(
// cspell:ignore tjoho
'tjoho' + getGraphId(relation.id1) + getGraphId(relation.id2) + JSON.stringify(relation)
);
g.setEdge(

View File

@ -289,6 +289,83 @@ const processSet = (input: string): string => {
return chars.join('');
};
// TODO: find a better method for detecting support. This interface was added in the MathML 4 spec.
// Firefox versions between [4,71] (0.47%) and Safari versions between [5,13.4] (0.17%) don't have this interface implemented but MathML is supported
export const isMathMLSupported = () => window.MathMLElement !== undefined;
export const katexRegex = /\$\$(.*)\$\$/g;
/**
* Whether or not a text has KaTeX delimiters
*
* @param text - The text to test
* @returns Whether or not the text has KaTeX delimiters
*/
export const hasKatex = (text: string): boolean => (text.match(katexRegex)?.length ?? 0) > 0;
/**
* Computes the minimum dimensions needed to display a div containing MathML
*
* @param text - The text to test
* @param config - Configuration for Mermaid
* @returns Object containing \{width, height\}
*/
export const calculateMathMLDimensions = async (text: string, config: MermaidConfig) => {
text = await renderKatex(text, config);
const divElem = document.createElement('div');
divElem.innerHTML = text;
divElem.id = 'katex-temp';
divElem.style.visibility = 'hidden';
divElem.style.position = 'absolute';
divElem.style.top = '0';
const body = document.querySelector('body');
body?.insertAdjacentElement('beforeend', divElem);
const dim = { width: divElem.clientWidth, height: divElem.clientHeight };
divElem.remove();
return dim;
};
/**
* Attempts to render and return the KaTeX portion of a string with MathML
*
* @param text - The text to test
* @param config - Configuration for Mermaid
* @returns String containing MathML if KaTeX is supported, or an error message if it is not and stylesheets aren't present
*/
export const renderKatex = async (text: string, config: MermaidConfig): Promise<string> => {
if (!hasKatex(text)) {
return text;
}
if (!isMathMLSupported() && !config.legacyMathML) {
return text.replace(katexRegex, 'MathML is unsupported in this environment.');
}
const { default: katex } = await import('katex');
return text
.split(lineBreakRegex)
.map((line) =>
hasKatex(line)
? `
<div style="display: flex; align-items: center; justify-content: center; white-space: nowrap;">
${line}
</div>
`
: `<div>${line}</div>`
)
.join('')
.replace(katexRegex, (_, c) =>
katex
.renderToString(c, {
throwOnError: true,
displayMode: true,
output: isMathMLSupported() ? 'mathml' : 'htmlAndMathml',
})
.replace(/\n/g, ' ')
.replace(/<annotation.*<\/annotation>/g, '')
);
};
export default {
getRows,
sanitizeText,

View File

@ -11,6 +11,7 @@ export interface RectData {
ry?: number;
attrs?: Record<string, string | number>;
anchor?: string;
name?: string;
}
export interface Bound {

View File

@ -21,6 +21,9 @@ export const drawRect = (element: SVG | Group, rectData: RectData): D3RectElemen
rectElement.attr('stroke', rectData.stroke);
rectElement.attr('width', rectData.width);
rectElement.attr('height', rectData.height);
if (rectData.name) {
rectElement.attr('name', rectData.name);
}
rectData.rx !== undefined && rectElement.attr('rx', rectData.rx);
rectData.ry !== undefined && rectElement.attr('ry', rectData.ry);

View File

@ -4,7 +4,7 @@ import { selectSvgElement } from '../../rendering-util/selectSvgElement.js';
import { configureSvgSize } from '../../setupGraphViewbox.js';
/**
* Draws a an info picture in the tag with id: id based on the graph definition in text.
* Draws an info picture in the tag with id: id based on the graph definition in text.
*
* @param _text - Mermaid graph definition.
* @param id - The text for the error
@ -12,12 +12,12 @@ import { configureSvgSize } from '../../setupGraphViewbox.js';
*/
export const draw = (_text: string, id: string, version: string) => {
log.debug('rendering svg for syntax error\n');
const svg: SVG = selectSvgElement(id);
const g: Group = svg.append('g');
svg.attr('viewBox', '0 0 2412 512');
configureSvgSize(svg, 100, 512, true);
const g: Group = svg.append('g');
g.append('path')
.attr('class', 'error-icon')
.attr(

View File

@ -30,7 +30,7 @@ let direction: string;
let version: string; // As in graph
// Functions to be run after graph rendering
let funs: ((element: Element) => void)[] = [];
let funs: ((element: Element) => void)[] = []; // cspell:ignore funs
const sanitizeText = (txt: string) => common.sanitizeText(txt, config);
@ -149,8 +149,8 @@ export const addSingleLink = function (_start: string, _end: string, type: any)
throw new Error(
`Edge limit exceeded. ${edges.length} edges found, but the limit is ${config.maxEdges}.
Initialize mermaid with maxEdges set to a higher number to allow more edges.
You cannot set this config via configuration inside the diagram as it is a secure config.
Initialize mermaid with maxEdges set to a higher number to allow more edges.
You cannot set this config via configuration inside the diagram as it is a secure config.
You have to call mermaid.initialize.`
);
}
@ -406,7 +406,7 @@ const setupToolTips = function (element: Element) {
const el = select(this);
const title = el.attr('title');
// Dont try to draw a tooltip if no data is provided
// Don't try to draw a tooltip if no data is provided
if (title === null) {
return;
}

View File

@ -5,7 +5,7 @@ import utils from '../../utils.js';
import { render } from '../../dagre-wrapper/index.js';
import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js';
import { log } from '../../logger.js';
import common, { evaluate } from '../common/common.js';
import common, { evaluate, renderKatex } from '../common/common.js';
import { interpolateToCurve, getStylesFromArray } from '../../utils.js';
import { setupGraphViewbox } from '../../setupGraphViewbox.js';
@ -27,12 +27,12 @@ export const setConf = function (cnf) {
* @param doc
* @param diagObj
*/
export const addVertices = function (vert, g, svgId, root, doc, diagObj) {
export const addVertices = async function (vert, g, svgId, root, doc, diagObj) {
const svg = root.select(`[id="${svgId}"]`);
const keys = Object.keys(vert);
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
keys.forEach(function (id) {
for (const id of keys) {
const vertex = vert[id];
/**
@ -59,10 +59,7 @@ export const addVertices = function (vert, g, svgId, root, doc, diagObj) {
if (evaluate(getConfig().flowchart.htmlLabels)) {
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
const node = {
label: vertexText.replace(
/fa[blrs]?:fa-[\w-]+/g,
(s) => `<i class='${s.replace(':', ' ')}'></i>`
),
label: vertexText,
};
vertexNode = addHtmlLabel(svg, node).node();
vertexNode.parentNode.removeChild(vertexNode);
@ -84,12 +81,12 @@ export const addVertices = function (vert, g, svgId, root, doc, diagObj) {
}
}
let radious = 0;
let radius = 0;
let _shape = '';
// Set the shape based parameters
switch (vertex.type) {
case 'round':
radious = 5;
radius = 5;
_shape = 'rect';
break;
case 'square':
@ -143,14 +140,16 @@ export const addVertices = function (vert, g, svgId, root, doc, diagObj) {
default:
_shape = 'rect';
}
const labelText = await renderKatex(vertexText, getConfig());
// Add the node
g.setNode(vertex.id, {
labelStyle: styles.labelStyle,
shape: _shape,
labelText: vertexText,
labelText,
labelType: vertex.labelType,
rx: radious,
ry: radious,
rx: radius,
ry: radius,
class: classStr,
style: styles.style,
id: vertex.id,
@ -170,9 +169,9 @@ export const addVertices = function (vert, g, svgId, root, doc, diagObj) {
labelStyle: styles.labelStyle,
labelType: vertex.labelType,
shape: _shape,
labelText: vertexText,
rx: radious,
ry: radious,
labelText,
rx: radius,
ry: radius,
class: classStr,
style: styles.style,
id: vertex.id,
@ -183,7 +182,7 @@ export const addVertices = function (vert, g, svgId, root, doc, diagObj) {
props: vertex.props,
padding: getConfig().flowchart.padding,
});
});
}
};
/**
@ -193,7 +192,7 @@ export const addVertices = function (vert, g, svgId, root, doc, diagObj) {
* @param {object} g The graph object
* @param diagObj
*/
export const addEdges = function (edges, g, diagObj) {
export const addEdges = async function (edges, g, diagObj) {
log.info('abc78 edges = ', edges);
let cnt = 0;
let linkIdCnt = {};
@ -207,7 +206,7 @@ export const addEdges = function (edges, g, diagObj) {
defaultLabelStyle = defaultStyles.labelStyle;
}
edges.forEach(function (edge) {
for (const edge of edges) {
cnt++;
// Identify Link
@ -315,9 +314,8 @@ export const addEdges = function (edges, g, diagObj) {
edgeData.arrowheadStyle = 'fill: #333';
edgeData.labelpos = 'c';
}
edgeData.labelType = edge.labelType;
edgeData.label = edge.text.replace(common.lineBreakRegex, '\n');
edgeData.label = await renderKatex(edge.text.replace(common.lineBreakRegex, '\n'), getConfig());
if (edge.style === undefined) {
edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none;';
@ -330,7 +328,7 @@ export const addEdges = function (edges, g, diagObj) {
// Add the edge to the graph
g.setEdge(edge.start, edge.end, edgeData, cnt);
});
}
};
/**
@ -427,8 +425,8 @@ export const draw = async function (text, id, _version, diagObj) {
g.setParent(subG.nodes[j], subG.id);
}
}
addVertices(vert, g, id, root, doc, diagObj);
addEdges(edges, g, diagObj);
await addVertices(vert, g, id, root, doc, diagObj);
await addEdges(edges, g, diagObj);
// Add custom shapes
// flowChartShapes.addToRenderV2(addShape);

View File

@ -15,7 +15,7 @@ describe('when using mermaid and ', function () {
flowDb.clear();
flowDb.setGen('gen-2');
});
it('should handle edges with text', () => {
it('should handle edges with text', async () => {
parser.parse('graph TD;A-->|text ex|B;');
flowDb.getVertices();
const edges = flowDb.getEdges();
@ -29,7 +29,7 @@ describe('when using mermaid and ', function () {
},
};
flowRenderer.addEdges(edges, mockG, diag);
await flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle edges without text', async function () {
@ -45,10 +45,10 @@ describe('when using mermaid and ', function () {
},
};
flowRenderer.addEdges(edges, mockG, diag);
await flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle open-ended edges', () => {
it('should handle open-ended edges', async () => {
parser.parse('graph TD;A---B;');
flowDb.getVertices();
const edges = flowDb.getEdges();
@ -61,10 +61,10 @@ describe('when using mermaid and ', function () {
},
};
flowRenderer.addEdges(edges, mockG, diag);
await flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle edges with styles defined', () => {
it('should handle edges with styles defined', async () => {
parser.parse('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;');
flowDb.getVertices();
const edges = flowDb.getEdges();
@ -78,9 +78,9 @@ describe('when using mermaid and ', function () {
},
};
flowRenderer.addEdges(edges, mockG, diag);
await flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle edges with interpolation defined', () => {
it('should handle edges with interpolation defined', async () => {
parser.parse('graph TD;A---B; linkStyle 0 interpolate basis');
flowDb.getVertices();
const edges = flowDb.getEdges();
@ -94,9 +94,9 @@ describe('when using mermaid and ', function () {
},
};
flowRenderer.addEdges(edges, mockG, diag);
await flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle edges with text and styles defined', () => {
it('should handle edges with text and styles defined', async () => {
parser.parse('graph TD;A---|the text|B; linkStyle 0 stroke:val1,stroke-width:val2;');
flowDb.getVertices();
const edges = flowDb.getEdges();
@ -111,10 +111,10 @@ describe('when using mermaid and ', function () {
},
};
flowRenderer.addEdges(edges, mockG, diag);
await flowRenderer.addEdges(edges, mockG, diag);
});
it('should set fill to "none" by default when handling edges', () => {
it('should set fill to "none" by default when handling edges', async () => {
parser.parse('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;');
flowDb.getVertices();
const edges = flowDb.getEdges();
@ -128,10 +128,10 @@ describe('when using mermaid and ', function () {
},
};
flowRenderer.addEdges(edges, mockG, diag);
await flowRenderer.addEdges(edges, mockG, diag);
});
it('should not set fill to none if fill is set in linkStyle', () => {
it('should not set fill to none if fill is set in linkStyle', async () => {
parser.parse('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2,fill:blue;');
flowDb.getVertices();
const edges = flowDb.getEdges();
@ -144,7 +144,7 @@ describe('when using mermaid and ', function () {
},
};
flowRenderer.addEdges(edges, mockG, diag);
await flowRenderer.addEdges(edges, mockG, diag);
});
});
});

View File

@ -5,7 +5,7 @@ import { render as Render } from 'dagre-d3-es';
import { applyStyle } from 'dagre-d3-es/src/dagre-js/util.js';
import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js';
import { log } from '../../logger.js';
import common, { evaluate } from '../common/common.js';
import common, { evaluate, renderKatex } from '../common/common.js';
import { interpolateToCurve, getStylesFromArray } from '../../utils.js';
import { setupGraphViewbox } from '../../setupGraphViewbox.js';
import flowChartShapes from './flowChartShapes.js';
@ -28,13 +28,13 @@ export const setConf = function (cnf) {
* @param _doc
* @param diagObj
*/
export const addVertices = function (vert, g, svgId, root, _doc, diagObj) {
export const addVertices = async function (vert, g, svgId, root, _doc, diagObj) {
const svg = !root ? select(`[id="${svgId}"]`) : root.select(`[id="${svgId}"]`);
const doc = !_doc ? document : _doc;
const keys = Object.keys(vert);
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
keys.forEach(function (id) {
for (const id of keys) {
const vertex = vert[id];
/**
@ -57,9 +57,12 @@ export const addVertices = function (vert, g, svgId, root, _doc, diagObj) {
if (evaluate(getConfig().flowchart.htmlLabels)) {
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
const node = {
label: vertexText.replace(
/fa[blrs]?:fa-[\w-]+/g,
(s) => `<i class='${s.replace(':', ' ')}'></i>`
label: await renderKatex(
vertexText.replace(
/fa[blrs]?:fa-[\w-]+/g, // cspell:disable-line
(s) => `<i class='${s.replace(':', ' ')}'></i>`
),
getConfig()
),
};
vertexNode = addHtmlLabel(svg, node).node();
@ -81,12 +84,12 @@ export const addVertices = function (vert, g, svgId, root, _doc, diagObj) {
vertexNode = svgLabel;
}
let radious = 0;
let radius = 0;
let _shape = '';
// Set the shape based parameters
switch (vertex.type) {
case 'round':
radious = 5;
radius = 5;
_shape = 'rect';
break;
case 'square':
@ -144,13 +147,13 @@ export const addVertices = function (vert, g, svgId, root, _doc, diagObj) {
labelStyle: styles.labelStyle,
shape: _shape,
label: vertexNode,
rx: radious,
ry: radious,
rx: radius,
ry: radius,
class: classStr,
style: styles.style,
id: diagObj.db.lookUpDomId(vertex.id),
});
});
}
};
/**
@ -160,7 +163,7 @@ export const addVertices = function (vert, g, svgId, root, _doc, diagObj) {
* @param {object} g The graph object
* @param diagObj
*/
export const addEdges = function (edges, g, diagObj) {
export const addEdges = async function (edges, g, diagObj) {
let cnt = 0;
let defaultStyle;
@ -172,7 +175,7 @@ export const addEdges = function (edges, g, diagObj) {
defaultLabelStyle = defaultStyles.labelStyle;
}
edges.forEach(function (edge) {
for (const edge of edges) {
cnt++;
// Identify Link
@ -239,9 +242,12 @@ export const addEdges = function (edges, g, diagObj) {
edgeData.labelType = 'html';
edgeData.label = `<span id="L-${linkId}" class="edgeLabel L-${linkNameStart}' L-${linkNameEnd}" style="${
edgeData.labelStyle
}">${edge.text.replace(
/fa[blrs]?:fa-[\w-]+/g,
(s) => `<i class='${s.replace(':', ' ')}'></i>`
}">${await renderKatex(
edge.text.replace(
/fa[blrs]?:fa-[\w-]+/g, // cspell:disable-line
(s) => `<i class='${s.replace(':', ' ')}'></i>`
),
getConfig()
)}</span>`;
} else {
edgeData.labelType = 'text';
@ -261,7 +267,7 @@ export const addEdges = function (edges, g, diagObj) {
// Add the edge to the graph
g.setEdge(diagObj.db.lookUpDomId(edge.start), diagObj.db.lookUpDomId(edge.end), edgeData, cnt);
});
}
};
/**
@ -284,7 +290,7 @@ export const getClasses = function (text, diagObj) {
* @param _version
* @param diagObj
*/
export const draw = function (text, id, _version, diagObj) {
export const draw = async function (text, id, _version, diagObj) {
log.info('Drawing flowchart');
const { securityLevel, flowchart: conf } = getConfig();
let sandboxElement;
@ -350,8 +356,8 @@ export const draw = function (text, id, _version, diagObj) {
g.setParent(diagObj.db.lookUpDomId(subG.nodes[j]), diagObj.db.lookUpDomId(subG.id));
}
}
addVertices(vert, g, id, root, doc, diagObj);
addEdges(edges, g, diagObj);
await addVertices(vert, g, id, root, doc, diagObj);
await addEdges(edges, g, diagObj);
// Create the renderer
const render = new Render();

View File

@ -27,7 +27,7 @@ describe('the flowchart renderer', function () {
['cylinder', 'cylinder'],
['group', 'rect'],
].forEach(function ([type, expectedShape, expectedRadios = 0]) {
it(`should add the correct shaped node to the graph for vertex type ${type}`, function () {
it(`should add the correct shaped node to the graph for vertex type ${type}`, async function () {
const fakeDiag = {
db: {
lookUpDomId: () => {
@ -41,7 +41,7 @@ describe('the flowchart renderer', function () {
addedNodes.push([id, object]);
},
};
addVertices(
await addVertices(
{
v1: {
type,
@ -70,7 +70,7 @@ describe('the flowchart renderer', function () {
['Multi<br>Line', 'Multi<br/>Line', 'Multi<br />Line', 'Multi<br\t/>Line'].forEach(function (
labelText
) {
it('should handle multiline texts with different line breaks', function () {
it('should handle multiline texts with different line breaks', async function () {
const addedNodes = [];
const fakeDiag = {
db: {
@ -84,7 +84,7 @@ describe('the flowchart renderer', function () {
addedNodes.push([id, object]);
},
};
addVertices(
await addVertices(
{
v1: {
type: 'rect',
@ -121,7 +121,7 @@ describe('the flowchart renderer', function () {
'color:#ccc;text-align:center;',
],
].forEach(function ([style, expectedStyle, expectedLabelStyle]) {
it(`should add the styles to style and/or labelStyle for style ${style}`, function () {
it(`should add the styles to style and/or labelStyle for style ${style}`, async function () {
const addedNodes = [];
const fakeDiag = {
db: {
@ -135,7 +135,7 @@ describe('the flowchart renderer', function () {
addedNodes.push([id, object]);
},
};
addVertices(
await addVertices(
{
v1: {
type: 'rect',
@ -160,7 +160,7 @@ describe('the flowchart renderer', function () {
});
});
it(`should add default class to all nodes which do not have another class assigned`, function () {
it(`should add default class to all nodes which do not have another class assigned`, async function () {
const addedNodes = [];
const mockG = {
setNode: function (id, object) {
@ -174,7 +174,7 @@ describe('the flowchart renderer', function () {
},
},
};
addVertices(
await addVertices(
{
v1: {
type: 'rect',
@ -206,7 +206,7 @@ describe('the flowchart renderer', function () {
});
describe('when adding edges to a graph', function () {
it('should handle multiline texts and set centered label position', function () {
it('should handle multiline texts and set centered label position', async function () {
const addedEdges = [];
const fakeDiag = {
db: {
@ -220,7 +220,7 @@ describe('the flowchart renderer', function () {
addedEdges.push(data);
},
};
addEdges(
await addEdges(
[
{ text: 'Multi<br>Line' },
{ text: 'Multi<br/>Line' },
@ -251,7 +251,7 @@ describe('the flowchart renderer', function () {
'fill:red;',
],
].forEach(function ([style, expectedStyle, expectedLabelStyle]) {
it(`should add the styles to style and/or labelStyle for style ${style}`, function () {
it(`should add the styles to style and/or labelStyle for style ${style}`, async function () {
const addedEdges = [];
const fakeDiag = {
db: {
@ -265,7 +265,7 @@ describe('the flowchart renderer', function () {
addedEdges.push(data);
},
};
addEdges([{ style: style, text: 'styling' }], mockG, fakeDiag);
await addEdges([{ style: style, text: 'styling' }], mockG, fakeDiag);
expect(addedEdges).toHaveLength(1);
expect(addedEdges[0]).toHaveProperty('style', expectedStyle);

View File

@ -292,15 +292,15 @@ graphConfig
| NEWLINE graphConfig
| GRAPH NODIR
{ yy.setDirection('TB');$$ = 'TB';}
| GRAPH DIR FirstStmtSeperator
| GRAPH DIR FirstStmtSeparator
{ yy.setDirection($DIR);$$ = $DIR;}
// | GRAPH SPACE TAGEND FirstStmtSeperator
// | GRAPH SPACE TAGEND FirstStmtSeparator
// { yy.setDirection("LR");$$ = $TAGEND;}
// | GRAPH SPACE TAGSTART FirstStmtSeperator
// | GRAPH SPACE TAGSTART FirstStmtSeparator
// { yy.setDirection("RL");$$ = $TAGSTART;}
// | GRAPH SPACE UP FirstStmtSeperator
// | GRAPH SPACE UP FirstStmtSeparator
// { yy.setDirection("BT");$$ = $UP;}
// | GRAPH SPACE DOWN FirstStmtSeperator
// | GRAPH SPACE DOWN FirstStmtSeparator
// { yy.setDirection("TB");$$ = $DOWN;}
;
@ -310,7 +310,7 @@ ending: endToken ending
endToken: NEWLINE | SPACE | EOF;
FirstStmtSeperator
FirstStmtSeparator
: SEMI | NEWLINE | spaceList NEWLINE ;
@ -328,8 +328,8 @@ spaceList
;
statement
: verticeStatement separator
{ /* console.warn('finat vs', $verticeStatement.nodes); */ $$=$verticeStatement.nodes}
: vertexStatement separator
{ /* console.warn('finat vs', $vertexStatement.nodes); */ $$=$vertexStatement.nodes}
| styleStatement separator
{$$=[];}
| linkStyleStatement separator
@ -357,10 +357,10 @@ statement
separator: NEWLINE | SEMI | EOF ;
verticeStatement: verticeStatement link node
{ /* console.warn('vs',$verticeStatement.stmt,$node); */ yy.addLink($verticeStatement.stmt,$node,$link); $$ = { stmt: $node, nodes: $node.concat($verticeStatement.nodes) } }
| verticeStatement link node spaceList
{ /* console.warn('vs',$verticeStatement.stmt,$node); */ yy.addLink($verticeStatement.stmt,$node,$link); $$ = { stmt: $node, nodes: $node.concat($verticeStatement.nodes) } }
vertexStatement: vertexStatement link node
{ /* console.warn('vs',$vertexStatement.stmt,$node); */ yy.addLink($vertexStatement.stmt,$node,$link); $$ = { stmt: $node, nodes: $node.concat($vertexStatement.nodes) } }
| vertexStatement link node spaceList
{ /* console.warn('vs',$vertexStatement.stmt,$node); */ yy.addLink($vertexStatement.stmt,$node,$link); $$ = { stmt: $node, nodes: $node.concat($vertexStatement.nodes) } }
|node spaceList {/*console.warn('noda', $node);*/ $$ = {stmt: $node, nodes:$node }}
|node { /*console.warn('noda', $node);*/ $$ = {stmt: $node, nodes:$node }}
;

View File

@ -66,6 +66,12 @@ const getStyles = (options: FlowChartStyleOptions) =>
// text-anchor: start;
// }
.node .katex path {
fill: #000;
stroke: #000;
stroke-width: 1px;
}
.node .label {
text-align: center;
}

View File

@ -256,32 +256,25 @@ const getStartDate = function (prevTime, dateFormat, str) {
str = str.trim();
// Test for after
const re = /^after\s+([\d\w- ]+)/;
const afterStatement = re.exec(str.trim());
const afterRePattern = /^after\s+(?<ids>[\d\w- ]+)/;
const afterStatement = afterRePattern.exec(str);
if (afterStatement !== null) {
// check all after ids and take the latest
let latestEndingTask = null;
afterStatement[1].split(' ').forEach(function (id) {
let latestTask = null;
for (const id of afterStatement.groups.ids.split(' ')) {
let task = findTaskById(id);
if (task !== undefined) {
if (!latestEndingTask) {
latestEndingTask = task;
} else {
if (task.endTime > latestEndingTask.endTime) {
latestEndingTask = task;
}
}
if (task !== undefined && (!latestTask || task.endTime > latestTask.endTime)) {
latestTask = task;
}
});
if (!latestEndingTask) {
const dt = new Date();
dt.setHours(0, 0, 0, 0);
return dt;
} else {
return latestEndingTask.endTime;
}
if (latestTask) {
return latestTask.endTime;
}
const today = new Date();
today.setHours(0, 0, 0, 0);
return today;
}
// Check for actual date set
@ -332,6 +325,7 @@ const getStartDate = function (prevTime, dateFormat, str) {
* @returns {[value: number, unit: dayjs.ManipulateType]} Arguments to pass to `dayjs.add()`
*/
const parseDuration = function (str) {
// cspell:disable-next-line
const statement = /^(\d+(?:\.\d+)?)([Mdhmswy]|ms)$/.exec(str.trim());
if (statement !== null) {
return [Number.parseFloat(statement[1]), statement[2]];
@ -343,13 +337,35 @@ const parseDuration = function (str) {
const getEndDate = function (prevTime, dateFormat, str, inclusive = false) {
str = str.trim();
// Check for actual date
let mDate = dayjs(str, dateFormat.trim(), true);
if (mDate.isValid()) {
if (inclusive) {
mDate = mDate.add(1, 'd');
// test for until
const untilRePattern = /^until\s+(?<ids>[\d\w- ]+)/;
const untilStatement = untilRePattern.exec(str);
if (untilStatement !== null) {
// check all until ids and take the earliest
let earliestTask = null;
for (const id of untilStatement.groups.ids.split(' ')) {
let task = findTaskById(id);
if (task !== undefined && (!earliestTask || task.startTime < earliestTask.startTime)) {
earliestTask = task;
}
}
return mDate.toDate();
if (earliestTask) {
return earliestTask.startTime;
}
const today = new Date();
today.setHours(0, 0, 0, 0);
return today;
}
// check for actual date
let parsedDate = dayjs(str, dateFormat.trim(), true);
if (parsedDate.isValid()) {
if (inclusive) {
parsedDate = parsedDate.add(1, 'd');
}
return parsedDate.toDate();
}
let endTime = dayjs(prevTime);

View File

@ -140,10 +140,10 @@ describe('when using the ganttDb', function () {
it('should handle relative start date based on id regardless of sections', function () {
ganttDb.setDateFormat('YYYY-MM-DD');
ganttDb.addSection('testa1');
ganttDb.addSection('sec1');
ganttDb.addTask('test1', 'id1,2013-01-01,2w');
ganttDb.addTask('test2', 'id2,after id3,1d');
ganttDb.addSection('testa2');
ganttDb.addSection('sec2');
ganttDb.addTask('test3', 'id3,after id1,2d');
const tasks = ganttDb.getTasks();
@ -158,6 +158,58 @@ describe('when using the ganttDb', function () {
expect(tasks[2].startTime).toEqual(new Date(2013, 0, 15));
expect(tasks[2].endTime).toEqual(new Date(2013, 0, 17));
});
it('should handle relative end date based on id regardless of sections', function () {
ganttDb.setDateFormat('YYYY-MM-DD');
ganttDb.addSection('sec1');
ganttDb.addTask('task1', 'id1,2013-01-01,until id3');
ganttDb.addSection('sec2');
ganttDb.addTask('task2', 'id2,2013-01-10,until id3');
ganttDb.addTask('task3', 'id3,2013-02-01,2d');
const tasks = ganttDb.getTasks();
expect(tasks[0].startTime).toEqual(new Date(2013, 0, 1));
expect(tasks[0].endTime).toEqual(new Date(2013, 1, 1));
expect(tasks[0].id).toEqual('id1');
expect(tasks[0].task).toEqual('task1');
expect(tasks[1].id).toEqual('id2');
expect(tasks[1].task).toEqual('task2');
expect(tasks[1].startTime).toEqual(new Date(2013, 0, 10));
expect(tasks[1].endTime).toEqual(new Date(2013, 1, 1));
});
it('should handle relative start date based on multiple id', function () {
ganttDb.setDateFormat('YYYY-MM-DD');
ganttDb.addSection('sec1');
ganttDb.addTask('task1', 'id1,after id2 id3 id4,1d');
ganttDb.addTask('task2', 'id2,2013-01-01,1d');
ganttDb.addTask('task3', 'id3,2013-02-01,3d');
ganttDb.addTask('task4', 'id4,2013-02-01,2d');
const tasks = ganttDb.getTasks();
expect(tasks[0].endTime).toEqual(new Date(2013, 1, 5));
expect(tasks[0].id).toEqual('id1');
expect(tasks[0].task).toEqual('task1');
});
it('should handle relative end date based on multiple id', function () {
ganttDb.setDateFormat('YYYY-MM-DD');
ganttDb.addSection('sec1');
ganttDb.addTask('task1', 'id1,2013-01-01,until id2 id3 id4');
ganttDb.addTask('task2', 'id2,2013-01-11,1d');
ganttDb.addTask('task3', 'id3,2013-02-10,1d');
ganttDb.addTask('task4', 'id4,2013-02-12,1d');
const tasks = ganttDb.getTasks();
expect(tasks[0].endTime).toEqual(new Date(2013, 0, 11));
expect(tasks[0].id).toEqual('id1');
expect(tasks[0].task).toEqual('task1');
});
it('should ignore weekends', function () {
ganttDb.setDateFormat('YYYY-MM-DD');
ganttDb.setExcludes('weekends 2019-02-06,friday');

View File

@ -178,7 +178,7 @@ export const draw = function (text, id, version, diagObj) {
// tasks are created based on their order of startTime
taskArray.sort(taskCompare);
makeGant(taskArray, w, h);
makeGantt(taskArray, w, h);
configureSvgSize(svg, h, w, conf.useMaxWidth);
@ -194,7 +194,7 @@ export const draw = function (text, id, version, diagObj) {
* @param pageWidth
* @param pageHeight
*/
function makeGant(tasks, pageWidth, pageHeight) {
function makeGantt(tasks, pageWidth, pageHeight) {
const barHeight = conf.barHeight;
const gap = barHeight + conf.barGap;
const topPadding = conf.topPadding;
@ -695,12 +695,12 @@ export const draw = function (text, id, version, diagObj) {
function vertLabels(theGap, theTopPad) {
let prevGap = 0;
const numOccurances = Object.keys(categoryHeights).map((d) => [d, categoryHeights[d]]);
const numOccurrences = Object.keys(categoryHeights).map((d) => [d, categoryHeights[d]]);
svg
.append('g') // without doing this, impossible to put grid lines behind text
.selectAll('text')
.data(numOccurances)
.data(numOccurrences)
.enter()
.append(function (d) {
const rows = d[0].split(common.lineBreakRegex);
@ -725,7 +725,7 @@ export const draw = function (text, id, version, diagObj) {
.attr('y', function (d, i) {
if (i > 0) {
for (let j = 0; j < i; j++) {
prevGap += numOccurances[i - 1][1];
prevGap += numOccurrences[i - 1][1];
return (d[1] * theGap) / 2 + prevGap * theGap + theTopPad;
}
} else {

View File

@ -118,6 +118,38 @@ describe('when parsing a gantt diagram it', function () {
expect(tasks[0].id).toEqual('des1');
expect(tasks[0].task).toEqual('Design jison grammar');
});
it('should handle a task with start/end time relative to other tasks', function () {
const str =
'gantt\n' +
'dateFormat YYYY-MM-DD\n' +
'title Adding gantt diagram functionality to mermaid\n' +
'section Documentation\n' +
'task A: a, 2024-01-27, 2024-01-28\n' +
'task B: b, after a, 2024-01-30\n' +
'task C: c, 2024-01-20, until a\n' +
'task D: d, after c, until b';
expect(parserFnConstructor(str)).not.toThrow();
const tasks = parser.yy.getTasks();
expect(tasks[0].startTime).toEqual(new Date(2024, 0, 27));
expect(tasks[0].endTime).toEqual(new Date(2024, 0, 28));
expect(tasks[0].id).toEqual('a');
expect(tasks[0].task).toEqual('task A');
expect(tasks[1].startTime).toEqual(new Date(2024, 0, 28));
expect(tasks[1].endTime).toEqual(new Date(2024, 0, 30));
expect(tasks[1].id).toEqual('b');
expect(tasks[1].task).toEqual('task B');
expect(tasks[2].startTime).toEqual(new Date(2024, 0, 20));
expect(tasks[2].endTime).toEqual(new Date(2024, 0, 27));
expect(tasks[2].id).toEqual('c');
expect(tasks[2].task).toEqual('task C');
expect(tasks[3].startTime).toEqual(new Date(2024, 0, 27));
expect(tasks[3].endTime).toEqual(new Date(2024, 0, 28));
expect(tasks[3].id).toEqual('d');
expect(tasks[3].task).toEqual('task D');
});
it.each(convert`
tags | milestone | done | crit | active
${'milestone'} | ${true} | ${false} | ${false} | ${false}

View File

@ -36,8 +36,8 @@ function getId() {
// * @param otherCommit
// */
// eslint-disable-next-line @cspell/spellchecker
// function isfastforwardable(currentCommit, otherCommit) {
// log.debug('Entering isfastforwardable:', currentCommit.id, otherCommit.id);
// function isFastForwardable(currentCommit, otherCommit) {
// log.debug('Entering isFastForwardable:', currentCommit.id, otherCommit.id);
// let cnt = 0;
// while (currentCommit.seq <= otherCommit.seq && currentCommit !== otherCommit && cnt < 1000) {
// cnt++;
@ -46,8 +46,8 @@ function getId() {
// if (Array.isArray(otherCommit.parent)) {
// log.debug('In merge commit:', otherCommit.parent);
// return (
// isfastforwardable(currentCommit, commits[otherCommit.parent[0]]) ||
// isfastforwardable(currentCommit, commits[otherCommit.parent[1]])
// isFastForwardable(currentCommit, commits[otherCommit.parent[0]]) ||
// isFastForwardable(currentCommit, commits[otherCommit.parent[1]])
// );
// } else {
// otherCommit = commits[otherCommit.parent];
@ -64,7 +64,7 @@ function getId() {
// function isReachableFrom(currentCommit, otherCommit) {
// const currentSeq = currentCommit.seq;
// const otherSeq = otherCommit.seq;
// if (currentSeq > otherSeq) return isfastforwardable(otherCommit, currentCommit);
// if (currentSeq > otherSeq) return isFastForwardable(otherCommit, currentCommit);
// return false;
// }
@ -231,7 +231,7 @@ export const merge = function (otherBranch, custom_id, override_type, custom_tag
// log.debug('Already merged');
// return;
// }
// if (isfastforwardable(currentCommit, otherCommit)) {
// if (isFastForwardable(currentCommit, otherCommit)) {
// branches[curBranch] = branches[otherBranch];
// head = commits[branches[curBranch]];
// } else {

View File

@ -295,7 +295,7 @@ function renderCommitHistory(svg, commitId, branches, direction) {
}
if (Array.isArray(commitId)) {
logger.debug('found merge commmit', commitId);
logger.debug('found merge commit', commitId);
renderCommitHistory(svg, commitId[0], branches, direction);
branchNum++;
renderCommitHistory(svg, commitId[1], branches, direction);

View File

@ -456,6 +456,10 @@ const drawArrow = (svg, commitA, commitB, allCommits) => {
let radius = 0;
let offset = 0;
let colorClassNum = branchPos[commitB.branch].index;
if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
colorClassNum = branchPos[commitA.branch].index;
}
let lineDef;
if (arrowNeedsRerouting) {
arc = 'A 10 10, 0, 0, 0,';
@ -470,7 +474,6 @@ const drawArrow = (svg, commitA, commitB, allCommits) => {
if (p1.x < p2.x) {
// Source commit is on branch position left of destination commit
// so render arrow rightward with colour of destination branch
colorClassNum = branchPos[commitB.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${lineX - radius} ${p1.y} ${arc2} ${lineX} ${
p1.y + offset
} L ${lineX} ${p2.y - radius} ${arc} ${lineX + offset} ${p2.y} L ${p2.x} ${p2.y}`;
@ -486,7 +489,6 @@ const drawArrow = (svg, commitA, commitB, allCommits) => {
if (p1.y < p2.y) {
// Source commit is on branch positioned above destination commit
// so render arrow downward with colour of destination branch
colorClassNum = branchPos[commitB.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${lineY - radius} ${arc} ${
p1.x + offset
} ${lineY} L ${p2.x - radius} ${lineY} ${arc2} ${p2.x} ${lineY + offset} L ${p2.x} ${p2.y}`;
@ -500,19 +502,22 @@ const drawArrow = (svg, commitA, commitB, allCommits) => {
}
}
} else {
arc = 'A 20 20, 0, 0, 0,';
arc2 = 'A 20 20, 0, 0, 1,';
radius = 20;
offset = 20;
if (dir === 'TB') {
if (p1.x < p2.x) {
arc = 'A 20 20, 0, 0, 0,';
arc2 = 'A 20 20, 0, 0, 1,';
radius = 20;
offset = 20;
// Figure out the color of the arrow,arrows going down take the color from the destination branch
colorClassNum = branchPos[commitB.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${p2.x - radius} ${p1.y} ${arc2} ${p2.x} ${
p1.y + offset
} L ${p2.x} ${p2.y}`;
if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y - radius} ${arc} ${p1.x + offset} ${
p2.y
} L ${p2.x} ${p2.y}`;
} else {
lineDef = `M ${p1.x} ${p1.y} L ${p2.x - radius} ${p1.y} ${arc2} ${p2.x} ${
p1.y + offset
} L ${p2.x} ${p2.y}`;
}
}
if (p1.x > p2.x) {
arc = 'A 20 20, 0, 0, 0,';
@ -520,46 +525,46 @@ const drawArrow = (svg, commitA, commitB, allCommits) => {
radius = 20;
offset = 20;
// Arrows going up take the color from the source branch
colorClassNum = branchPos[commitA.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y - radius} ${arc2} ${p1.x - offset} ${
p2.y
} L ${p2.x} ${p2.y}`;
if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y - radius} ${arc2} ${p1.x - offset} ${
p2.y
} L ${p2.x} ${p2.y}`;
} else {
lineDef = `M ${p1.x} ${p1.y} L ${p2.x + radius} ${p1.y} ${arc} ${p2.x} ${
p1.y + offset
} L ${p2.x} ${p2.y}`;
}
}
if (p1.x === p2.x) {
colorClassNum = branchPos[commitA.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${p1.x + radius} ${p1.y} ${arc} ${p1.x + offset} ${
p2.y + radius
} L ${p2.x} ${p2.y}`;
lineDef = `M ${p1.x} ${p1.y} L ${p2.x} ${p2.y}`;
}
} else {
if (p1.y < p2.y) {
arc = 'A 20 20, 0, 0, 0,';
radius = 20;
offset = 20;
// Arrows going up take the color from the target branch
colorClassNum = branchPos[commitB.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y - radius} ${arc} ${p1.x + offset} ${p2.y} L ${
p2.x
} ${p2.y}`;
if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
lineDef = `M ${p1.x} ${p1.y} L ${p2.x - radius} ${p1.y} ${arc2} ${p2.x} ${
p1.y + offset
} L ${p2.x} ${p2.y}`;
} else {
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y - radius} ${arc} ${p1.x + offset} ${
p2.y
} L ${p2.x} ${p2.y}`;
}
}
if (p1.y > p2.y) {
arc = 'A 20 20, 0, 0, 0,';
radius = 20;
offset = 20;
// Arrows going up take the color from the source branch
colorClassNum = branchPos[commitA.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${p2.x - radius} ${p1.y} ${arc} ${p2.x} ${p1.y - offset} L ${
p2.x
} ${p2.y}`;
if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
lineDef = `M ${p1.x} ${p1.y} L ${p2.x - radius} ${p1.y} ${arc} ${p2.x} ${
p1.y - offset
} L ${p2.x} ${p2.y}`;
} else {
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y + radius} ${arc2} ${p1.x + offset} ${
p2.y
} L ${p2.x} ${p2.y}`;
}
}
if (p1.y === p2.y) {
colorClassNum = branchPos[commitA.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y - radius} ${arc} ${p1.x + offset} ${p2.y} L ${
p2.x
} ${p2.y}`;
lineDef = `M ${p1.x} ${p1.y} L ${p2.x} ${p2.y}`;
}
}
}

View File

@ -84,7 +84,7 @@ options
| NL
;
body
: /*emmpty*/ {$$ = []}
: /*empty*/ {$$ = []}
| body line {$1.push($2); $$=$1;}
;
line

View File

@ -133,7 +133,7 @@ const type2Str = (type: number) => {
case nodeType.BANG:
return 'bang';
case nodeType.HEXAGON:
return 'hexgon';
return 'hexgon'; // cspell: disable-line
default:
return 'no-border';
}

View File

@ -51,7 +51,7 @@ export interface PieDB extends DiagramDB {
getDiagramTitle: () => string;
setAccTitle: (title: string) => void;
getAccTitle: () => string;
setAccDescription: (describetion: string) => void;
setAccDescription: (description: string) => void;
getAccDescription: () => string;
// diagram db

View File

@ -362,6 +362,8 @@ export const draw = (text, id, _version, diagObj) => {
svg.attr('viewBox', `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`);
};
// cspell:ignore txts
export default {
draw,
};

View File

@ -11,14 +11,13 @@
%lex
%options case-insensitive
%options easy_keword_rules
%x escaped_text
%x csv
// as per section 6.1 of RFC 2234 [2]
COMMA \u002C
CR \u000D
CR \u000D
LF \u000A
CRLF \u000D\u000A
ESCAPED_QUOTE \u0022
@ -32,7 +31,7 @@ TEXTDATA [\u0020-\u0021\u0023-\u002B\u002D-\u007E]
<INITIAL,csv>({CRLF}|{LF}) { return 'NEWLINE' }
<INITIAL,csv>{COMMA} { return 'COMMA' }
<INITIAL,csv>{DQUOTE} { this.pushState('escaped_text'); return 'DQUOTE'; }
<INITIAL,csv>{TEXTDATA}* { return 'NON_ESCAPED_TEXT' }
<INITIAL,csv>{TEXTDATA}* { return 'NON_ESCAPED_TEXT' }
<INITIAL,csv,escaped_text>{DQUOTE}(?!{DQUOTE}) {this.popState('escaped_text'); return 'DQUOTE'; } // unescaped DQUOTE closes string
<INITIAL,csv,escaped_text>({TEXTDATA}|{COMMA}|{CR}|{LF}|{DQUOTE}{DQUOTE})* { return 'ESCAPED_TEXT'; }
@ -65,5 +64,3 @@ field
escaped: DQUOTE ESCAPED_TEXT DQUOTE { $$=$ESCAPED_TEXT; };
non_escaped: NON_ESCAPED_TEXT { $$=$NON_ESCAPED_TEXT; };

View File

@ -209,7 +209,7 @@ Note right of Bob: Bob thinks
Bob-->Alice: I am good thanks!`;
await mermaidAPI.parse(str);
diagram.renderer.draw(str, 'tst', '1.2.3', diagram); // needs to be rendered for the correct value of visibility auto numbers
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram); // needs to be rendered for the correct value of visibility auto numbers
expect(diagram.db.showSequenceNumbers()).toBe(false);
});
it('should show sequence numbers when autonumber is enabled', async () => {
@ -221,7 +221,7 @@ Note right of Bob: Bob thinks
Bob-->Alice: I am good thanks!`;
await mermaidAPI.parse(str);
diagram.renderer.draw(str, 'tst', '1.2.3', diagram); // needs to be rendered for the correct value of visibility auto numbers
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram); // needs to be rendered for the correct value of visibility auto numbers
expect(diagram.db.showSequenceNumbers()).toBe(true);
});
@ -1648,7 +1648,7 @@ participant Alice`;
// mermaidAPI.reinitialize({ sequence: { textPlacement: textPlacement } });
await mermaidAPI.parse(str);
// diagram.renderer.setConf(mermaidAPI.getConfig().sequence);
diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
const { bounds } = diagram.renderer.bounds.getBounds();
expect(bounds.startx).toBe(0);
@ -1679,7 +1679,7 @@ Note over Alice: Alice thinks
expect(mermaidAPI.getConfig().sequence.mirrorActors).toBeFalsy();
await mermaidAPI.parse(str);
diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
const { bounds, models } = diagram.renderer.bounds.getBounds();
expect(bounds.startx).toBe(0);
@ -1695,7 +1695,7 @@ participant Alice
Note left of Alice: Alice thinks`;
await mermaidAPI.parse(str);
diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
const { bounds, models } = diagram.renderer.bounds.getBounds();
expect(bounds.startx).toBe(-(conf.width / 2) - conf.actorMargin / 2);
@ -1711,7 +1711,7 @@ participant Alice
Note right of Alice: Alice thinks`;
await mermaidAPI.parse(str);
diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
const { bounds, models } = diagram.renderer.bounds.getBounds();
expect(bounds.startx).toBe(0);
@ -1726,7 +1726,7 @@ sequenceDiagram
Alice->Bob: Hello Bob, how are you?`;
await mermaidAPI.parse(str);
diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
const { bounds, models } = diagram.renderer.bounds.getBounds();
expect(bounds.startx).toBe(0);
@ -1744,7 +1744,7 @@ end
Alice->Bob: Hello Bob, how are you?`;
await mermaidAPI.parse(str);
diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
const { bounds, models } = diagram.renderer.bounds.getBounds();
expect(bounds.startx).toBe(0);
@ -1759,7 +1759,7 @@ sequenceDiagram
Alice->Bob: Hello Bob, how are you?`;
await mermaidAPI.parse(str);
diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
const { bounds, models } = diagram.renderer.bounds.getBounds();
const mermaid = mermaidAPI.getConfig();
@ -1779,7 +1779,7 @@ wrap
Alice->Bob: Hello Bob, how are you?`;
await mermaidAPI.parse(str);
diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
const msgs = diagram.db.getMessages();
const { bounds, models } = diagram.renderer.bounds.getBounds();
@ -1800,7 +1800,7 @@ Note over Bob,Alice: Looks back
`;
// mermaidAPI.initialize({logLevel:0})
await mermaidAPI.parse(str);
diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
const { bounds, models } = diagram.renderer.bounds.getBounds();
expect(bounds.startx).toBe(0);
@ -1815,7 +1815,7 @@ Alice->Bob: Hello Bob, how are you?
Bob->Alice: Fine!`;
await mermaidAPI.parse(str);
diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
const { bounds, models } = diagram.renderer.bounds.getBounds();
expect(bounds.startx).toBe(0);
@ -1831,7 +1831,7 @@ Note right of Bob: Bob thinks
Bob->Alice: Fine!`;
await mermaidAPI.parse(str);
diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
const { bounds, models } = diagram.renderer.bounds.getBounds();
expect(bounds.startx).toBe(0);
@ -1850,7 +1850,7 @@ Note left of Alice: Bob thinks
Bob->Alice: Fine!`;
await mermaidAPI.parse(str);
diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
const { bounds, models } = diagram.renderer.bounds.getBounds();
expect(bounds.startx).toBe(-(conf.width / 2) - conf.actorMargin / 2);
@ -1867,7 +1867,7 @@ Note left of Alice: Bob thinks
Bob->>Alice: Fine!`;
await mermaidAPI.parse(str);
diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
const { bounds, models } = diagram.renderer.bounds.getBounds();
const msgs = diagram.db.getMessages();
@ -1888,7 +1888,7 @@ Note left of Alice: Bob thinks
Bob->>Alice: Fine!`;
await mermaidAPI.parse(str);
diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
const { bounds, models } = diagram.renderer.bounds.getBounds();
const msgs = diagram.db.getMessages();
@ -1911,7 +1911,7 @@ Note left of Alice: Bob thinks
Bob->>Alice: Fine!`;
await mermaidAPI.parse(str);
diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
const { bounds, models } = diagram.renderer.bounds.getBounds();
const msgs = diagram.db.getMessages();
@ -1933,7 +1933,7 @@ Note left of Alice: Bob thinks
Bob->>Alice: Fine!`;
// mermaidAPI.initialize({ logLevel: 0 });
await mermaidAPI.parse(str);
diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
const { bounds, models } = diagram.renderer.bounds.getBounds();
const msgs = diagram.db.getMessages();
@ -1957,7 +1957,7 @@ loop Cheers
Bob->Alice: Fine!
end`;
await mermaidAPI.parse(str);
diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
const { bounds, models } = diagram.renderer.bounds.getBounds();
expect(bounds.startx).toBe(0);
@ -1975,7 +1975,7 @@ end`;
end
`;
await mermaidAPI.parse(str);
diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
const { bounds, models } = diagram.renderer.bounds.getBounds();
expect(bounds.startx).toBe(0);
expect(bounds.starty).toBe(0);
@ -2022,7 +2022,7 @@ sequenceDiagram
participant Alice`;
diagram.renderer.bounds.init();
await mermaidAPI.parse(str);
diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
const { bounds, models } = diagram.renderer.bounds.getBounds();
expect(bounds.startx).toBe(0);

View File

@ -1,8 +1,8 @@
// @ts-nocheck TODO: fix file
import { select } from 'd3';
import svgDraw, { ACTOR_TYPE_WIDTH, drawText, fixLifeLineHeights } from './svgDraw.js';
import svgDraw, { drawKatex, ACTOR_TYPE_WIDTH, drawText, fixLifeLineHeights } from './svgDraw.js';
import { log } from '../../logger.js';
import common from '../common/common.js';
import common, { calculateMathMLDimensions, hasKatex } from '../common/common.js';
import * as svgDrawCommon from '../common/svgDrawCommon.js';
import { getConfig } from '../../diagram-api/diagramAPI.js';
import assignWithDepth from '../../assignWithDepth.js';
@ -237,7 +237,7 @@ interface NoteModel {
* @param elem - The diagram to draw to.
* @param noteModel - Note model options.
*/
const drawNote = function (elem: any, noteModel: NoteModel) {
const drawNote = async function (elem: any, noteModel: NoteModel) {
bounds.bumpVerticalPos(conf.boxMargin);
noteModel.height = conf.boxMargin;
noteModel.starty = bounds.getVerticalPos();
@ -263,7 +263,7 @@ const drawNote = function (elem: any, noteModel: NoteModel) {
textObj.textMargin = conf.noteMargin;
textObj.valign = 'center';
const textElem = drawText(g, textObj);
const textElem = hasKatex(textObj.text) ? await drawKatex(g, textObj) : drawText(g, textObj);
const textHeight = Math.round(
textElem
@ -311,15 +311,20 @@ const actorFont = (cnf) => {
* @param msgModel - The model containing fields describing a message
* @returns `lineStartY` - The Y coordinate at which the message line starts
*/
function boundMessage(_diagram, msgModel): number {
async function boundMessage(_diagram, msgModel): Promise<number> {
bounds.bumpVerticalPos(10);
const { startx, stopx, message } = msgModel;
const lines = common.splitBreaks(message).length;
const textDims = utils.calculateTextDimensions(message, messageFont(conf));
const lineHeight = textDims.height / lines;
msgModel.height += lineHeight;
const isKatexMsg = hasKatex(message);
const textDims = isKatexMsg
? await calculateMathMLDimensions(message, getConfig())
: utils.calculateTextDimensions(message, messageFont(conf));
bounds.bumpVerticalPos(lineHeight);
if (!isKatexMsg) {
const lineHeight = textDims.height / lines;
msgModel.height += lineHeight;
bounds.bumpVerticalPos(lineHeight);
}
let lineStartY;
let totalOffset = textDims.height - 10;
@ -360,7 +365,7 @@ function boundMessage(_diagram, msgModel): number {
* @param lineStartY - The Y coordinate at which the message line starts
* @param diagObj - The diagram object.
*/
const drawMessage = function (diagram, msgModel, lineStartY: number, diagObj: Diagram) {
const drawMessage = async function (diagram, msgModel, lineStartY: number, diagObj: Diagram) {
const { startx, stopx, starty, message, type, sequenceIndex, sequenceVisible } = msgModel;
const textDims = utils.calculateTextDimensions(message, messageFont(conf));
const textObj = svgDrawCommon.getTextObj();
@ -378,7 +383,9 @@ const drawMessage = function (diagram, msgModel, lineStartY: number, diagObj: Di
textObj.textMargin = conf.wrapPadding;
textObj.tspan = false;
drawText(diagram, textObj);
hasKatex(textObj.text)
? await drawKatex(diagram, textObj, { startx, stopx, starty: lineStartY })
: drawText(diagram, textObj);
const textWidth = textDims.width;
@ -478,7 +485,7 @@ const drawMessage = function (diagram, msgModel, lineStartY: number, diagObj: Di
}
};
const addActorRenderingData = function (
const addActorRenderingData = async function (
diagram,
actors,
createdActors,
@ -548,12 +555,12 @@ const addActorRenderingData = function (
bounds.bumpVerticalPos(maxHeight);
};
export const drawActors = function (diagram, actors, actorKeys, isFooter) {
export const drawActors = async function (diagram, actors, actorKeys, isFooter) {
if (!isFooter) {
for (const actorKey of actorKeys) {
const actor = actors[actorKey];
// Draw the box with the attached line
svgDraw.drawActor(diagram, actor, conf, false);
await svgDraw.drawActor(diagram, actor, conf, false);
}
} else {
let maxHeight = 0;
@ -563,7 +570,7 @@ export const drawActors = function (diagram, actors, actorKeys, isFooter) {
if (!actor.stopy) {
actor.stopy = bounds.getVerticalPos();
}
const height = svgDraw.drawActor(diagram, actor, conf, true);
const height = await svgDraw.drawActor(diagram, actor, conf, true);
maxHeight = common.getMax(maxHeight, height);
}
bounds.bumpVerticalPos(maxHeight + conf.boxMargin);
@ -746,7 +753,7 @@ function adjustCreatedDestroyedData(
* @param _version - Mermaid version from package.json
* @param diagObj - A standard diagram containing the db and the text and type etc of the diagram
*/
export const draw = function (_text: string, id: string, _version: string, diagObj: Diagram) {
export const draw = async function (_text: string, id: string, _version: string, diagObj: Diagram) {
const { securityLevel, sequence } = getConfig();
conf = sequence;
// Handle root and Document for when rendering in sandbox mode
@ -776,8 +783,8 @@ export const draw = function (_text: string, id: string, _version: string, diagO
const title = diagObj.db.getDiagramTitle();
const hasBoxes = diagObj.db.hasAtLeastOneBox();
const hasBoxTitles = diagObj.db.hasAtLeastOneBoxWithTitle();
const maxMessageWidthPerActor = getMaxMessageWidthPerActor(actors, messages, diagObj);
conf.height = calculateActorMargins(actors, maxMessageWidthPerActor, boxes);
const maxMessageWidthPerActor = await getMaxMessageWidthPerActor(actors, messages, diagObj);
conf.height = await calculateActorMargins(actors, maxMessageWidthPerActor, boxes);
svgDraw.insertComputerIcon(diagram);
svgDraw.insertDatabaseIcon(diagram);
@ -799,8 +806,8 @@ export const draw = function (_text: string, id: string, _version: string, diagO
actorKeys = actorKeys.filter((actorKey) => newActors.has(actorKey));
}
addActorRenderingData(diagram, actors, createdActors, actorKeys, 0, messages, false);
const loopWidths = calculateLoopBounds(messages, actors, maxMessageWidthPerActor, diagObj);
await addActorRenderingData(diagram, actors, createdActors, actorKeys, 0, messages, false);
const loopWidths = await calculateLoopBounds(messages, actors, maxMessageWidthPerActor, diagObj);
// The arrow head definition is attached to the svg once
svgDraw.insertArrowHead(diagram);
@ -834,14 +841,15 @@ export const draw = function (_text: string, id: string, _version: string, diagO
let sequenceIndexStep = 1;
const messagesToDraw = [];
const backgrounds = [];
messages.forEach(function (msg, index) {
let index = 0;
for (const msg of messages) {
let loopModel, noteModel, msgModel;
switch (msg.type) {
case diagObj.db.LINETYPE.NOTE:
bounds.resetVerticalPos();
noteModel = msg.noteModel;
drawNote(diagram, noteModel);
await drawNote(diagram, noteModel);
break;
case diagObj.db.LINETYPE.ACTIVE_START:
bounds.newActivation(msg, diagram, actors);
@ -860,7 +868,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
break;
case diagObj.db.LINETYPE.LOOP_END:
loopModel = bounds.endLoop();
svgDraw.drawLoop(diagram, loopModel, 'loop', conf);
await svgDraw.drawLoop(diagram, loopModel, 'loop', conf);
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
bounds.models.addLoop(loopModel);
break;
@ -886,7 +894,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
break;
case diagObj.db.LINETYPE.OPT_END:
loopModel = bounds.endLoop();
svgDraw.drawLoop(diagram, loopModel, 'opt', conf);
await svgDraw.drawLoop(diagram, loopModel, 'opt', conf);
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
bounds.models.addLoop(loopModel);
break;
@ -910,7 +918,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
break;
case diagObj.db.LINETYPE.ALT_END:
loopModel = bounds.endLoop();
svgDraw.drawLoop(diagram, loopModel, 'alt', conf);
await svgDraw.drawLoop(diagram, loopModel, 'alt', conf);
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
bounds.models.addLoop(loopModel);
break;
@ -936,7 +944,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
break;
case diagObj.db.LINETYPE.PAR_END:
loopModel = bounds.endLoop();
svgDraw.drawLoop(diagram, loopModel, 'par', conf);
await svgDraw.drawLoop(diagram, loopModel, 'par', conf);
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
bounds.models.addLoop(loopModel);
break;
@ -969,7 +977,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
break;
case diagObj.db.LINETYPE.CRITICAL_END:
loopModel = bounds.endLoop();
svgDraw.drawLoop(diagram, loopModel, 'critical', conf);
await svgDraw.drawLoop(diagram, loopModel, 'critical', conf);
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
bounds.models.addLoop(loopModel);
break;
@ -984,7 +992,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
break;
case diagObj.db.LINETYPE.BREAK_END:
loopModel = bounds.endLoop();
svgDraw.drawLoop(diagram, loopModel, 'break', conf);
await svgDraw.drawLoop(diagram, loopModel, 'break', conf);
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
bounds.models.addLoop(loopModel);
break;
@ -994,7 +1002,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
msgModel.starty = bounds.getVerticalPos();
msgModel.sequenceIndex = sequenceIndex;
msgModel.sequenceVisible = diagObj.db.showSequenceNumbers();
const lineStartY = boundMessage(diagram, msgModel);
const lineStartY = await boundMessage(diagram, msgModel);
adjustCreatedDestroyedData(
msg,
msgModel,
@ -1026,20 +1034,23 @@ export const draw = function (_text: string, id: string, _version: string, diagO
) {
sequenceIndex = sequenceIndex + sequenceIndexStep;
}
});
index++;
}
log.debug('createdActors', createdActors);
log.debug('destroyedActors', destroyedActors);
await drawActors(diagram, actors, actorKeys, false);
drawActors(diagram, actors, actorKeys, false);
messagesToDraw.forEach((e) => drawMessage(diagram, e.messageModel, e.lineStartY, diagObj));
for (const e of messagesToDraw) {
await drawMessage(diagram, e.messageModel, e.lineStartY, diagObj);
}
if (conf.mirrorActors) {
drawActors(diagram, actors, actorKeys, true);
await drawActors(diagram, actors, actorKeys, true);
}
backgrounds.forEach((e) => svgDraw.drawBackgroundRect(diagram, e));
fixLifeLineHeights(diagram, actors, actorKeys, conf);
bounds.models.boxes.forEach(function (box) {
for (const box of bounds.models.boxes) {
box.height = bounds.getVerticalPos() - box.y;
bounds.insert(box.x, box.y, box.x + box.width, box.height);
box.startx = box.x;
@ -1047,8 +1058,8 @@ export const draw = function (_text: string, id: string, _version: string, diagO
box.stopx = box.startx + box.width;
box.stopy = box.starty + box.height;
box.stroke = 'rgb(0,0,0, 0.5)';
svgDraw.drawBox(diagram, box, conf);
});
await svgDraw.drawBox(diagram, box, conf);
}
if (hasBoxes) {
bounds.bumpVerticalPos(conf.boxMargin);
@ -1114,25 +1125,25 @@ export const draw = function (_text: string, id: string, _version: string, diagO
* @param diagObj - The diagram object.
* @returns The max message width of each actor.
*/
function getMaxMessageWidthPerActor(
async function getMaxMessageWidthPerActor(
actors: { [id: string]: any },
messages: any[],
diagObj: Diagram
): { [id: string]: number } {
): Promise<{ [id: string]: number }> {
const maxMessageWidthPerActor = {};
messages.forEach(function (msg) {
for (const msg of messages) {
if (actors[msg.to] && actors[msg.from]) {
const actor = actors[msg.to];
// If this is the first actor, and the message is left of it, no need to calculate the margin
if (msg.placement === diagObj.db.PLACEMENT.LEFTOF && !actor.prevActor) {
return;
continue;
}
// If this is the last actor, and the message is right of it, no need to calculate the margin
if (msg.placement === diagObj.db.PLACEMENT.RIGHTOF && !actor.nextActor) {
return;
continue;
}
const isNote = msg.placement !== undefined;
@ -1142,7 +1153,9 @@ function getMaxMessageWidthPerActor(
const wrappedMessage = msg.wrap
? utils.wrapLabel(msg.message, conf.width - 2 * conf.wrapPadding, textFont)
: msg.message;
const messageDimensions = utils.calculateTextDimensions(wrappedMessage, textFont);
const messageDimensions = hasKatex(wrappedMessage)
? await calculateMathMLDimensions(msg.message, getConfig())
: utils.calculateTextDimensions(wrappedMessage, textFont);
const messageWidth = messageDimensions.width + 2 * conf.wrapPadding;
/*
@ -1207,7 +1220,7 @@ function getMaxMessageWidthPerActor(
}
}
}
});
}
log.debug('maxMessageWidthPerActor:', maxMessageWidthPerActor);
return maxMessageWidthPerActor;
@ -1238,13 +1251,13 @@ const getRequiredPopupWidth = function (actor) {
* @param actorToMessageWidth - A map of actor key max message width it holds
* @param boxes - The boxes around the actors if any
*/
function calculateActorMargins(
async function calculateActorMargins(
actors: { [id: string]: any },
actorToMessageWidth: ReturnType<typeof getMaxMessageWidthPerActor>,
actorToMessageWidth: Awaited<ReturnType<typeof getMaxMessageWidthPerActor>>,
boxes
) {
let maxHeight = 0;
Object.keys(actors).forEach((prop) => {
for (const prop of Object.keys(actors)) {
const actor = actors[prop];
if (actor.wrap) {
actor.description = utils.wrapLabel(
@ -1253,14 +1266,17 @@ function calculateActorMargins(
actorFont(conf)
);
}
const actDims = utils.calculateTextDimensions(actor.description, actorFont(conf));
const actDims = hasKatex(actor.description)
? await calculateMathMLDimensions(actor.description, getConfig())
: utils.calculateTextDimensions(actor.description, actorFont(conf));
actor.width = actor.wrap
? conf.width
: common.getMax(conf.width, actDims.width + 2 * conf.wrapPadding);
actor.height = actor.wrap ? common.getMax(actDims.height, conf.height) : conf.height;
maxHeight = common.getMax(maxHeight, actor.height);
});
}
for (const actorKey in actorToMessageWidth) {
const actor = actors[actorKey];
@ -1311,15 +1327,17 @@ function calculateActorMargins(
return common.getMax(maxHeight, conf.height);
}
const buildNoteModel = function (msg, actors, diagObj) {
const buildNoteModel = async function (msg, actors, diagObj) {
const startx = actors[msg.from].x;
const stopx = actors[msg.to].x;
const shouldWrap = msg.wrap && msg.message;
let textDimensions = utils.calculateTextDimensions(
shouldWrap ? utils.wrapLabel(msg.message, conf.width, noteFont(conf)) : msg.message,
noteFont(conf)
);
let textDimensions: { width: number; height: number; lineHeight?: number } = hasKatex(msg.message)
? await calculateMathMLDimensions(msg.message, getConfig())
: utils.calculateTextDimensions(
shouldWrap ? utils.wrapLabel(msg.message, conf.width, noteFont(conf)) : msg.message,
noteFont(conf)
);
const noteModel = {
width: shouldWrap
? conf.width
@ -1477,12 +1495,12 @@ const buildMessageModel = function (msg, actors, diagObj) {
};
};
const calculateLoopBounds = function (messages, actors, _maxWidthPerActor, diagObj) {
const calculateLoopBounds = async function (messages, actors, _maxWidthPerActor, diagObj) {
const loops = {};
const stack = [];
let current, noteModel, msgModel;
messages.forEach(function (msg) {
for (const msg of messages) {
msg.id = utils.random({ length: 10 });
switch (msg.type) {
case diagObj.db.LINETYPE.LOOP_START:
@ -1545,7 +1563,7 @@ const calculateLoopBounds = function (messages, actors, _maxWidthPerActor, diagO
}
const isNote = msg.placement !== undefined;
if (isNote) {
noteModel = buildNoteModel(msg, actors, diagObj);
noteModel = await buildNoteModel(msg, actors, diagObj);
msg.noteModel = noteModel;
stack.forEach((stk) => {
current = stk;
@ -1584,7 +1602,7 @@ const calculateLoopBounds = function (messages, actors, _maxWidthPerActor, diagO
});
}
}
});
}
bounds.activations = [];
log.debug('Loop type widths:', loops);
return loops;

View File

@ -1,8 +1,9 @@
import common from '../common/common.js';
import common, { calculateMathMLDimensions, hasKatex, renderKatex } from '../common/common.js';
import * as svgDrawCommon from '../common/svgDrawCommon.js';
import { addFunction } from '../../interactionDb.js';
import { ZERO_WIDTH_SPACE, parseFontSize } from '../../utils.js';
import { sanitizeUrl } from '@braintree/sanitize-url';
import * as configApi from '../../config.js';
export const ACTOR_TYPE_WIDTH = 18 * 2;
const TOP_ACTOR_CLASS = 'actor-top';
@ -75,14 +76,55 @@ export const drawPopup = function (elem, actor, minMenuWidth, textAttrs, forceMe
return { height: rectData.height + linkY, width: menuWidth };
};
const popupMenuToggle = function (popid) {
const popupMenuToggle = function (popId) {
return (
"var pu = document.getElementById('" +
popid +
popId +
"'); if (pu != null) { pu.style.display = pu.style.display == 'block' ? 'none' : 'block'; }"
);
};
export const drawKatex = async function (elem, textData, msgModel = null) {
let textElem = elem.append('foreignObject');
const lines = await renderKatex(textData.text, configApi.getConfig());
const divElem = textElem
.append('xhtml:div')
.attr('style', 'width: fit-content;')
.attr('xmlns', 'http://www.w3.org/1999/xhtml')
.html(lines);
const dim = divElem.node().getBoundingClientRect();
textElem.attr('height', Math.round(dim.height)).attr('width', Math.round(dim.width));
if (textData.class === 'noteText') {
const rectElem = elem.node().firstChild;
rectElem.setAttribute('height', dim.height + 2 * textData.textMargin);
const rectDim = rectElem.getBBox();
textElem
.attr('x', Math.round(rectDim.x + rectDim.width / 2 - dim.width / 2))
.attr('y', Math.round(rectDim.y + rectDim.height / 2 - dim.height / 2));
} else if (msgModel) {
let { startx, stopx, starty } = msgModel;
if (startx > stopx) {
const temp = startx;
startx = stopx;
stopx = temp;
}
textElem.attr('x', Math.round(startx + Math.abs(startx - stopx) / 2 - dim.width / 2));
if (textData.class === 'loopText') {
textElem.attr('y', Math.round(starty));
} else {
textElem.attr('y', Math.round(starty - dim.height));
}
}
return [textElem];
};
export const drawText = function (elem, textData) {
let prevTextHeight = 0;
let textHeight = 0;
@ -282,13 +324,13 @@ export const fixLifeLineHeights = (diagram, actors, actorKeys, conf) => {
* @param {any} conf - DrawText implementation discriminator object
* @param {boolean} isFooter - If the actor is the footer one
*/
const drawActorTypeParticipant = function (elem, actor, conf, isFooter) {
const drawActorTypeParticipant = async function (elem, actor, conf, isFooter) {
const actorY = isFooter ? actor.stopy : actor.starty;
const center = actor.x + actor.width / 2;
const centerY = actorY + 5;
const boxpluslineGroup = elem.append('g').lower();
var g = boxpluslineGroup;
const boxplusLineGroup = elem.append('g').lower();
var g = boxplusLineGroup;
if (!isFooter) {
actorCnt++;
@ -306,7 +348,7 @@ const drawActorTypeParticipant = function (elem, actor, conf, isFooter) {
.attr('stroke-width', '0.5px')
.attr('stroke', '#999');
g = boxpluslineGroup.append('g');
g = boxplusLineGroup.append('g');
actor.actorCnt = actorCnt;
if (actor.links != null) {
@ -333,6 +375,7 @@ const drawActorTypeParticipant = function (elem, actor, conf, isFooter) {
rect.class = cssclass;
rect.rx = 3;
rect.ry = 3;
rect.name = actor.name;
const rectElem = drawRect(g, rect);
actor.rectData = rect;
@ -345,7 +388,7 @@ const drawActorTypeParticipant = function (elem, actor, conf, isFooter) {
}
}
_drawTextCandidateFunc(conf)(
await _drawTextCandidateFunc(conf, hasKatex(actor.description))(
actor.description,
g,
rect.x,
@ -366,7 +409,7 @@ const drawActorTypeParticipant = function (elem, actor, conf, isFooter) {
return height;
};
const drawActorTypeActor = function (elem, actor, conf, isFooter) {
const drawActorTypeActor = async function (elem, actor, conf, isFooter) {
const actorY = isFooter ? actor.stopy : actor.starty;
const center = actor.x + actor.width / 2;
const centerY = actorY + 80;
@ -397,6 +440,7 @@ const drawActorTypeActor = function (elem, actor, conf, isFooter) {
cssClass += ` ${TOP_ACTOR_CLASS}`;
}
actElem.attr('class', cssClass);
actElem.attr('name', actor.name);
const rect = svgDrawCommon.getNoteRect();
rect.x = actor.x;
@ -446,7 +490,7 @@ const drawActorTypeActor = function (elem, actor, conf, isFooter) {
const bounds = actElem.node().getBBox();
actor.height = bounds.height;
_drawTextCandidateFunc(conf)(
await _drawTextCandidateFunc(conf, hasKatex(actor.description))(
actor.description,
actElem,
rect.x,
@ -460,21 +504,21 @@ const drawActorTypeActor = function (elem, actor, conf, isFooter) {
return actor.height;
};
export const drawActor = function (elem, actor, conf, isFooter) {
export const drawActor = async function (elem, actor, conf, isFooter) {
switch (actor.type) {
case 'actor':
return drawActorTypeActor(elem, actor, conf, isFooter);
return await drawActorTypeActor(elem, actor, conf, isFooter);
case 'participant':
return drawActorTypeParticipant(elem, actor, conf, isFooter);
return await drawActorTypeParticipant(elem, actor, conf, isFooter);
}
};
export const drawBox = function (elem, box, conf) {
const boxplustextGroup = elem.append('g');
const g = boxplustextGroup;
export const drawBox = async function (elem, box, conf) {
const boxplusTextGroup = elem.append('g');
const g = boxplusTextGroup;
drawBackgroundRect(g, box);
if (box.name) {
_drawTextCandidateFunc(conf)(
await _drawTextCandidateFunc(conf)(
box.name,
g,
box.x,
@ -521,7 +565,7 @@ export const drawActivation = function (elem, bounds, verticalPos, conf, actorAc
* @param {any} conf - Diagram configuration
* @returns {any}
*/
export const drawLoop = function (elem, loopModel, labelText, conf) {
export const drawLoop = async function (elem, loopModel, labelText, conf) {
const {
boxMargin,
boxTextMargin,
@ -583,10 +627,10 @@ export const drawLoop = function (elem, loopModel, labelText, conf) {
txt.fontWeight = fontWeight;
txt.wrap = true;
let textElem = drawText(g, txt);
let textElem = hasKatex(txt.text) ? await drawKatex(g, txt, loopModel) : drawText(g, txt);
if (loopModel.sectionTitles !== undefined) {
loopModel.sectionTitles.forEach(function (item, idx) {
for (const [idx, item] of Object.entries(loopModel.sectionTitles)) {
if (item.message) {
txt.text = item.message;
txt.x = loopModel.startx + (loopModel.stopx - loopModel.startx) / 2;
@ -599,7 +643,13 @@ export const drawLoop = function (elem, loopModel, labelText, conf) {
txt.fontSize = fontSize;
txt.fontWeight = fontWeight;
txt.wrap = loopModel.wrap;
textElem = drawText(g, txt);
if (hasKatex(txt.text)) {
loopModel.starty = loopModel.sections[idx].y;
await drawKatex(g, txt, loopModel);
} else {
drawText(g, txt);
}
let sectionHeight = Math.round(
textElem
.map((te) => (te._groups || te)[0][0].getBBox().height)
@ -607,7 +657,7 @@ export const drawLoop = function (elem, loopModel, labelText, conf) {
);
loopModel.sections[idx].height += sectionHeight - (boxMargin + boxTextMargin);
}
});
}
}
loopModel.height = Math.round(loopModel.stopy - loopModel.starty);
@ -884,6 +934,41 @@ const _drawTextCandidateFunc = (function () {
_setTextAttrs(text, textAttrs);
}
/**
*
* @param content
* @param g
* @param x
* @param y
* @param width
* @param height
* @param textAttrs
* @param conf
*/
async function byKatex(content, g, x, y, width, height, textAttrs, conf) {
// TODO duplicate render calls, optimize
const dim = await calculateMathMLDimensions(content, configApi.getConfig());
const s = g.append('switch');
const f = s
.append('foreignObject')
.attr('x', x + width / 2 - dim.width / 2)
.attr('y', y + height / 2 - dim.height / 2)
.attr('width', dim.width)
.attr('height', dim.height);
const text = f.append('xhtml:div').style('height', '100%').style('width', '100%');
text
.append('div')
.style('text-align', 'center')
.style('vertical-align', 'middle')
.html(await renderKatex(content, configApi.getConfig()));
byTspan(content, s, x, y, width, height, textAttrs, conf);
_setTextAttrs(text, textAttrs);
}
/**
* @param {any} toText
* @param {any} fromTextAttrsDict
@ -896,7 +981,10 @@ const _drawTextCandidateFunc = (function () {
}
}
return function (conf) {
return function (conf, hasKatex = false) {
if (hasKatex) {
return byKatex;
}
return conf.textPlacement === 'fo' ? byFo : conf.textPlacement === 'old' ? byText : byTspan;
};
})();

View File

@ -206,7 +206,7 @@ export const addTitleAndBox = (g, stateDef, altBkg) => {
g.insert('rect', ':first-child')
.attr('x', startX)
.attr('y', lineY)
.attr('class', altBkg ? 'alt-composit' : 'composit')
.attr('class', altBkg ? 'alt-composit' : 'composit') // cspell:disable-line
.attr('width', width)
.attr(
'height',
@ -482,11 +482,11 @@ export const drawEdge = function (elem, path, relation) {
.attr('x', x)
.attr('y', y + titleHeight);
const boundstmp = title.node().getBBox();
maxWidth = Math.max(maxWidth, boundstmp.width);
minX = Math.min(minX, boundstmp.x);
const boundsTmp = title.node().getBBox();
maxWidth = Math.max(maxWidth, boundsTmp.width);
minX = Math.min(minX, boundsTmp.x);
log.info(boundstmp.x, x, y + titleHeight);
log.info(boundsTmp.x, x, y + titleHeight);
if (titleHeight === 0) {
const titleBox = title.node().getBBox();

View File

@ -260,7 +260,7 @@ export const addState = function (
if (classes) {
log.info('Setting state classes', trimmedId, classes);
const classesList = typeof classes === 'string' ? [classes] : classes;
classesList.forEach((klass) => setCssClass(trimmedId, klass.trim()));
classesList.forEach((cssClass) => setCssClass(trimmedId, cssClass.trim()));
}
if (styles) {

View File

@ -202,4 +202,7 @@ g.stateGroup line {
}
`;
// todo: change composit to composite
// cspell:ignore composit
export default getStyles;

View File

@ -53,7 +53,7 @@ export const addTask = function (period, length, event) {
};
export const addEvent = function (event) {
// fetch current task with currnetTaskId
// fetch current task with currentTaskId
const currentTask = rawTasks.find((task) => task.id === currentTaskId - 1);
//add event to the events array
currentTask.events.push(event);

View File

@ -27,14 +27,14 @@ export function getAxis(
axisThemeConfig: XYChartAxisThemeConfig,
tmpSVGGroup: Group
): Axis {
const textDimansionCalculator = new TextDimensionCalculatorWithFont(tmpSVGGroup);
const textDimensionCalculator = new TextDimensionCalculatorWithFont(tmpSVGGroup);
if (isBandAxisData(data)) {
return new BandAxis(
axisConfig,
axisThemeConfig,
data.categories,
data.title,
textDimansionCalculator
textDimensionCalculator
);
}
return new LinearAxis(
@ -42,6 +42,6 @@ export function getAxis(
axisThemeConfig,
[data.min, data.max],
data.title,
textDimansionCalculator
textDimensionCalculator
);
}

View File

@ -112,7 +112,7 @@ export class Orchestrator {
}
}
private calculateHorizonatalSpace() {
private calculateHorizontalSpace() {
let availableWidth = this.chartConfig.width;
let availableHeight = this.chartConfig.height;
let titleYEnd = 0;
@ -174,7 +174,7 @@ export class Orchestrator {
private calculateSpace() {
if (this.chartConfig.chartOrientation === 'horizontal') {
this.calculateHorizonatalSpace();
this.calculateHorizontalSpace();
} else {
this.calculateVerticalSpace();
}

View File

@ -173,6 +173,7 @@ function sidebarConfig() {
{ text: 'Mermaid Configuration Options', link: '/config/schema-docs/config' },
{ text: 'Directives', link: '/config/directives' },
{ text: 'Theming', link: '/config/theming' },
{ text: 'Math', link: '/config/math' },
{ text: 'Accessibility', link: '/config/accessibility' },
{ text: 'Mermaid CLI', link: '/config/mermaidCLI' },
{ text: 'FAQ', link: '/config/faq' },

View File

@ -130,7 +130,7 @@ You might see _lint_ or _formatting_ warnings. Those are ok during this step.
## Workflow
Contributing process is very simple and strightforward:
Contributing process is very simple and straightforward:
```mermaid-nocode
flowchart LR
@ -371,13 +371,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!
@ -403,7 +403,7 @@ 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"]
```
### Running the Documentation Website Locally
@ -521,3 +521,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 --->

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