mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-14 06:43:25 +08:00
Merge branch 'release/9.4.0'
This commit is contained in:
commit
98bec36f81
@ -3,4 +3,5 @@ dist/**
|
||||
docs/Setup.md
|
||||
cypress.config.js
|
||||
cypress/plugins/index.js
|
||||
coverage
|
||||
coverage
|
||||
*.json
|
150
.eslintrc.cjs
Normal file
150
.eslintrc.cjs
Normal file
@ -0,0 +1,150 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es6: true,
|
||||
'jest/globals': true,
|
||||
node: true,
|
||||
},
|
||||
root: true,
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
experimentalObjectRestSpread: true,
|
||||
jsx: true,
|
||||
},
|
||||
tsconfigRootDir: __dirname,
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 2020,
|
||||
allowAutomaticSingleRunInference: true,
|
||||
project: ['./tsconfig.eslint.json', './packages/*/tsconfig.json'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
},
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:json/recommended',
|
||||
'plugin:markdown/recommended',
|
||||
'plugin:@cspell/recommended',
|
||||
'prettier',
|
||||
],
|
||||
plugins: [
|
||||
'@typescript-eslint',
|
||||
'no-only-tests',
|
||||
'html',
|
||||
'jest',
|
||||
'jsdoc',
|
||||
'json',
|
||||
'@cspell',
|
||||
'lodash',
|
||||
'unicorn',
|
||||
],
|
||||
rules: {
|
||||
curly: 'error',
|
||||
'no-console': 'error',
|
||||
'no-prototype-builtins': 'off',
|
||||
'no-unused-vars': 'off',
|
||||
'cypress/no-async-tests': 'off',
|
||||
'@typescript-eslint/no-floating-promises': 'error',
|
||||
'@typescript-eslint/no-misused-promises': 'error',
|
||||
'@typescript-eslint/ban-ts-comment': [
|
||||
'error',
|
||||
{
|
||||
'ts-expect-error': 'allow-with-description',
|
||||
'ts-ignore': 'allow-with-description',
|
||||
'ts-nocheck': 'allow-with-description',
|
||||
'ts-check': 'allow-with-description',
|
||||
minimumDescriptionLength: 10,
|
||||
},
|
||||
],
|
||||
'json/*': ['error', 'allowComments'],
|
||||
'@cspell/spellchecker': [
|
||||
'error',
|
||||
{
|
||||
checkIdentifiers: false,
|
||||
checkStrings: false,
|
||||
checkStringTemplates: false,
|
||||
},
|
||||
],
|
||||
'no-empty': [
|
||||
'error',
|
||||
{
|
||||
allowEmptyCatch: true,
|
||||
},
|
||||
],
|
||||
'no-only-tests/no-only-tests': 'error',
|
||||
'lodash/import-scope': ['error', 'method'],
|
||||
'unicorn/better-regex': 'error',
|
||||
'unicorn/no-abusive-eslint-disable': 'error',
|
||||
'unicorn/no-array-push-push': 'error',
|
||||
'unicorn/no-for-loop': 'error',
|
||||
'unicorn/no-instanceof-array': 'error',
|
||||
'unicorn/no-typeof-undefined': 'error',
|
||||
'unicorn/no-unnecessary-await': 'error',
|
||||
'unicorn/no-unsafe-regex': 'warn',
|
||||
'unicorn/no-useless-promise-resolve-reject': 'error',
|
||||
'unicorn/prefer-array-find': 'error',
|
||||
'unicorn/prefer-array-flat-map': 'error',
|
||||
'unicorn/prefer-array-index-of': 'error',
|
||||
'unicorn/prefer-array-some': 'error',
|
||||
'unicorn/prefer-default-parameters': 'error',
|
||||
'unicorn/prefer-includes': 'error',
|
||||
'unicorn/prefer-negative-index': 'error',
|
||||
'unicorn/prefer-object-from-entries': 'error',
|
||||
'unicorn/prefer-string-starts-ends-with': 'error',
|
||||
'unicorn/prefer-string-trim-start-end': 'error',
|
||||
'unicorn/string-content': 'error',
|
||||
'unicorn/prefer-spread': 'error',
|
||||
'unicorn/no-lonely-if': 'error',
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['cypress/**', 'demos/**'],
|
||||
rules: {
|
||||
'no-console': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.{js,jsx,mjs,cjs}'],
|
||||
extends: ['plugin:jsdoc/recommended'],
|
||||
rules: {
|
||||
'jsdoc/check-indentation': 'off',
|
||||
'jsdoc/check-alignment': 'off',
|
||||
'jsdoc/check-line-alignment': 'off',
|
||||
'jsdoc/multiline-blocks': 'off',
|
||||
'jsdoc/newline-after-description': 'off',
|
||||
'jsdoc/tag-lines': 'off',
|
||||
'jsdoc/require-param-description': 'off',
|
||||
'jsdoc/require-param-type': 'off',
|
||||
'jsdoc/require-returns': 'off',
|
||||
'jsdoc/require-returns-description': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.{ts,tsx}'],
|
||||
plugins: ['tsdoc'],
|
||||
rules: {
|
||||
'tsdoc/syntax': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.spec.{ts,js}', 'cypress/**', 'demos/**', '**/docs/**'],
|
||||
rules: {
|
||||
'jsdoc/require-jsdoc': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.html', '*.md', '**/*.md/*'],
|
||||
rules: {
|
||||
'no-var': 'error',
|
||||
'no-undef': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-floating-promises': 'off',
|
||||
'@typescript-eslint/no-misused-promises': 'off',
|
||||
},
|
||||
parserOptions: {
|
||||
project: null,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
137
.eslintrc.json
137
.eslintrc.json
@ -1,137 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
"jest/globals": true,
|
||||
"node": true
|
||||
},
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
"experimentalObjectRestSpread": true,
|
||||
"jsx": true
|
||||
},
|
||||
"sourceType": "module"
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:json/recommended",
|
||||
"plugin:markdown/recommended",
|
||||
"plugin:@cspell/recommended",
|
||||
"prettier"
|
||||
],
|
||||
"plugins": [
|
||||
"@typescript-eslint",
|
||||
"no-only-tests",
|
||||
"html",
|
||||
"jest",
|
||||
"jsdoc",
|
||||
"json",
|
||||
"@cspell",
|
||||
"lodash",
|
||||
"unicorn"
|
||||
],
|
||||
"rules": {
|
||||
"curly": "error",
|
||||
"no-console": "error",
|
||||
"no-prototype-builtins": "off",
|
||||
"no-unused-vars": "off",
|
||||
"cypress/no-async-tests": "off",
|
||||
"@typescript-eslint/ban-ts-comment": [
|
||||
"error",
|
||||
{
|
||||
"ts-expect-error": "allow-with-description",
|
||||
"ts-ignore": "allow-with-description",
|
||||
"ts-nocheck": "allow-with-description",
|
||||
"ts-check": "allow-with-description",
|
||||
"minimumDescriptionLength": 10
|
||||
}
|
||||
],
|
||||
"json/*": ["error", "allowComments"],
|
||||
"@cspell/spellchecker": [
|
||||
"error",
|
||||
{
|
||||
"checkIdentifiers": false,
|
||||
"checkStrings": false,
|
||||
"checkStringTemplates": false
|
||||
}
|
||||
],
|
||||
"no-empty": [
|
||||
"error",
|
||||
{
|
||||
"allowEmptyCatch": true
|
||||
}
|
||||
],
|
||||
"no-only-tests/no-only-tests": "error",
|
||||
"lodash/import-scope": ["error", "method"],
|
||||
"unicorn/better-regex": "error",
|
||||
"unicorn/no-abusive-eslint-disable": "error",
|
||||
"unicorn/no-array-push-push": "error",
|
||||
"unicorn/no-for-loop": "error",
|
||||
"unicorn/no-instanceof-array": "error",
|
||||
"unicorn/no-typeof-undefined": "error",
|
||||
"unicorn/no-unnecessary-await": "error",
|
||||
"unicorn/no-unsafe-regex": "warn",
|
||||
"unicorn/no-useless-promise-resolve-reject": "error",
|
||||
"unicorn/prefer-array-find": "error",
|
||||
"unicorn/prefer-array-flat-map": "error",
|
||||
"unicorn/prefer-array-index-of": "error",
|
||||
"unicorn/prefer-array-some": "error",
|
||||
"unicorn/prefer-default-parameters": "error",
|
||||
"unicorn/prefer-includes": "error",
|
||||
"unicorn/prefer-negative-index": "error",
|
||||
"unicorn/prefer-object-from-entries": "error",
|
||||
"unicorn/prefer-string-starts-ends-with": "error",
|
||||
"unicorn/prefer-string-trim-start-end": "error",
|
||||
"unicorn/string-content": "error",
|
||||
"unicorn/prefer-spread": "error",
|
||||
"unicorn/no-lonely-if": "error"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["cypress/**", "demos/**"],
|
||||
"rules": {
|
||||
"no-console": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.{js,jsx,mjs,cjs}"],
|
||||
"extends": ["plugin:jsdoc/recommended"],
|
||||
"rules": {
|
||||
"jsdoc/check-indentation": "off",
|
||||
"jsdoc/check-alignment": "off",
|
||||
"jsdoc/check-line-alignment": "off",
|
||||
"jsdoc/multiline-blocks": "off",
|
||||
"jsdoc/newline-after-description": "off",
|
||||
"jsdoc/tag-lines": "off",
|
||||
"jsdoc/require-param-description": "off",
|
||||
"jsdoc/require-param-type": "off",
|
||||
"jsdoc/require-returns": "off",
|
||||
"jsdoc/require-returns-description": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.{ts,tsx}"],
|
||||
"plugins": ["tsdoc"],
|
||||
"rules": {
|
||||
"tsdoc/syntax": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.spec.{ts,js}", "cypress/**", "demos/**", "**/docs/**"],
|
||||
"rules": {
|
||||
"jsdoc/require-jsdoc": "off",
|
||||
"@typescript-eslint/no-unused-vars": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.html", "*.md", "**/*.md/*"],
|
||||
"rules": {
|
||||
"no-var": "error",
|
||||
"no-undef": "off",
|
||||
"@typescript-eslint/no-unused-vars": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
4
.github/FUNDING.yml
vendored
4
.github/FUNDING.yml
vendored
@ -1,6 +1,8 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [knsv]
|
||||
github:
|
||||
- knsv
|
||||
- sidharthv96
|
||||
#patreon: # Replace with a single Patreon username
|
||||
#open_collective: # Replace with a single Open Collective username
|
||||
#ko_fi: # Replace with a single Ko-fi username
|
||||
|
1
.github/pull_request_template.md
vendored
1
.github/pull_request_template.md
vendored
@ -14,4 +14,5 @@ Make sure you
|
||||
|
||||
- [ ] :book: have read the [contribution guidelines](https://github.com/mermaid-js/mermaid/blob/develop/CONTRIBUTING.md)
|
||||
- [ ] :computer: have added unit/e2e tests (if appropriate)
|
||||
- [ ] :notebook: have added documentation (if appropriate)
|
||||
- [ ] :bookmark: targeted `develop` branch
|
||||
|
8
.github/workflows/e2e.yml
vendored
8
.github/workflows/e2e.yml
vendored
@ -32,6 +32,7 @@ jobs:
|
||||
# and run all Cypress tests
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@v4
|
||||
id: cypress
|
||||
# If CYPRESS_RECORD_KEY is set, run in parallel on all containers
|
||||
# Otherwise (e.g. if running from fork), we run on a single container only
|
||||
if: ${{ ( env.CYPRESS_RECORD_KEY != '' ) || ( matrix.containers == 1 ) }}
|
||||
@ -44,3 +45,10 @@ jobs:
|
||||
parallel: ${{ secrets.CYPRESS_RECORD_KEY != '' }}
|
||||
env:
|
||||
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
if: ${{ failure() && steps.cypress.conclusion == 'failure' }}
|
||||
with:
|
||||
name: error-snapshots
|
||||
path: cypress/snapshots/**/__diff_output__/*
|
||||
|
3
.github/workflows/link-checker.yml
vendored
3
.github/workflows/link-checker.yml
vendored
@ -13,11 +13,10 @@ on:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- develop
|
||||
- master
|
||||
schedule:
|
||||
# * is a special character in YAML so you have to quote this string
|
||||
- cron: '30 8 * * 5'
|
||||
- cron: '30 8 * * *'
|
||||
|
||||
jobs:
|
||||
linkChecker:
|
||||
|
16
.github/workflows/lint.yml
vendored
16
.github/workflows/lint.yml
vendored
@ -7,6 +7,7 @@ on:
|
||||
- opened
|
||||
- synchronize
|
||||
- ready_for_review
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
@ -36,7 +37,20 @@ jobs:
|
||||
CYPRESS_CACHE_FOLDER: .cache/Cypress
|
||||
|
||||
- name: Run Linting
|
||||
run: pnpm run lint
|
||||
shell: bash
|
||||
run: |
|
||||
if ! pnpm run lint; then
|
||||
# print a nice error message on lint failure
|
||||
ERROR_MESSAGE='Running `pnpm run lint` failed.'
|
||||
ERROR_MESSAGE+=' Running `pnpm run lint:fix` may fix this issue. '
|
||||
ERROR_MESSAGE+=" If this error doesn't occur on your local machine,"
|
||||
ERROR_MESSAGE+=' make sure your packages are up-to-date by running `pnpm install`.'
|
||||
ERROR_MESSAGE+=' You may also need to delete your prettier cache by running'
|
||||
ERROR_MESSAGE+=' `rm ./node_modules/.cache/prettier/.prettier-cache`.'
|
||||
echo "::error title=Lint failure::${ERROR_MESSAGE}"
|
||||
# make sure to return an error exitcode so that GitHub actions shows a red-cross
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Verify Docs
|
||||
id: verifyDocs
|
||||
|
@ -1,5 +1,11 @@
|
||||
export default {
|
||||
'!(docs/**/*)*.{ts,js,json,html,md,mts}': ['eslint --fix', 'prettier --write'],
|
||||
'!(docs/**/*)*.{ts,js,json,html,md,mts}': [
|
||||
'eslint --cache --cache-strategy content --fix',
|
||||
// don't cache prettier yet, since we use `prettier-plugin-jsdoc`,
|
||||
// and prettier doesn't invalidate cache on plugin updates"
|
||||
// https://prettier.io/docs/en/cli.html#--cache
|
||||
'prettier --write',
|
||||
],
|
||||
'cSpell.json': ['ts-node-esm scripts/fixCSpell.ts'],
|
||||
'**/*.jison': ['pnpm -w run lint:jison'],
|
||||
};
|
||||
|
@ -9,5 +9,8 @@ https://mkdocs.org/
|
||||
https://osawards.com/javascript/#nominees
|
||||
https://osawards.com/javascript/2019
|
||||
|
||||
# Timeout error, maybe Twitter has anti-bot defences against GitHub's CI servers?
|
||||
https://twitter.com/mermaidjs_
|
||||
|
||||
# Don't check files that are generated during the build via `pnpm docs:code`
|
||||
packages/mermaid/src/docs/config/setup/*
|
||||
|
@ -36,16 +36,11 @@ const packageOptions = {
|
||||
packageName: 'mermaid',
|
||||
file: 'mermaid.ts',
|
||||
},
|
||||
'mermaid-mindmap': {
|
||||
name: 'mermaid-mindmap',
|
||||
packageName: 'mermaid-mindmap',
|
||||
'mermaid-example-diagram': {
|
||||
name: 'mermaid-example-diagram',
|
||||
packageName: 'mermaid-example-diagram',
|
||||
file: 'detector.ts',
|
||||
},
|
||||
// 'mermaid-example-diagram-detector': {
|
||||
// name: 'mermaid-example-diagram-detector',
|
||||
// packageName: 'mermaid-example-diagram',
|
||||
// file: 'detector.ts',
|
||||
// },
|
||||
};
|
||||
|
||||
interface BuildOptions {
|
||||
@ -119,11 +114,7 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions)
|
||||
|
||||
if (watch && config.build) {
|
||||
config.build.watch = {
|
||||
include: [
|
||||
'packages/mermaid-mindmap/src/**',
|
||||
'packages/mermaid/src/**',
|
||||
// 'packages/mermaid-example-diagram/src/**',
|
||||
],
|
||||
include: ['packages/mermaid-example-diagram/src/**', 'packages/mermaid/src/**'],
|
||||
};
|
||||
}
|
||||
|
||||
@ -146,10 +137,9 @@ const main = async () => {
|
||||
};
|
||||
|
||||
if (watch) {
|
||||
build(getBuildConfig({ minify: false, watch, core: true, entryName: 'mermaid' }));
|
||||
build(getBuildConfig({ minify: false, watch, core: false, entryName: 'mermaid' }));
|
||||
if (!mermaidOnly) {
|
||||
build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-mindmap' }));
|
||||
// build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-example-diagram' }));
|
||||
build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-example-diagram' }));
|
||||
}
|
||||
} else if (visualize) {
|
||||
await build(getBuildConfig({ minify: false, core: true, entryName: 'mermaid' }));
|
||||
|
@ -1,6 +1,5 @@
|
||||
import express, { NextFunction, Request, Response } from 'express';
|
||||
import { createServer as createViteServer } from 'vite';
|
||||
// import { getBuildConfig } from './build';
|
||||
|
||||
const cors = (req: Request, res: Response, next: NextFunction) => {
|
||||
res.header('Access-Control-Allow-Origin', '*');
|
||||
@ -22,8 +21,8 @@ async function createServer() {
|
||||
|
||||
app.use(cors);
|
||||
app.use(express.static('./packages/mermaid/dist'));
|
||||
// app.use(express.static('./packages/mermaid-example-diagram/dist'));
|
||||
app.use(express.static('./packages/mermaid-example-diagram/dist'));
|
||||
app.use(express.static('./packages/mermaid-mindmap/dist'));
|
||||
app.use(vite.middlewares);
|
||||
app.use(express.static('demos'));
|
||||
app.use(express.static('cypress/platform'));
|
||||
@ -33,5 +32,4 @@ async function createServer() {
|
||||
});
|
||||
}
|
||||
|
||||
// build(getBuildConfig({ minify: false, watch: true }));
|
||||
createServer();
|
||||
|
@ -1,6 +1,6 @@
|
||||
# mermaid
|
||||
|
||||
[![Build CI Status](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml/badge.svg)](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml) [![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.com/package/mermaid) [![npm minified gzipped bundle size](https://img.shields.io/bundlephobia/minzip/mermaid)](https://bundlephobia.com/package/mermaid) [![Coverage Status](https://coveralls.io/repos/github/mermaid-js/mermaid/badge.svg?branch=master)](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid) [![NPM](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid) [![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) [![Twitter Follow](https://img.shields.io/twitter/follow/mermaidjs_?style=social)](https://twitter.com/mermaidjs_)
|
||||
[![Build CI Status](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml/badge.svg)](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml) [![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.com/package/mermaid) [![npm minified gzipped bundle size](https://img.shields.io/bundlephobia/minzip/mermaid)](https://bundlephobia.com/package/mermaid) [![Coverage Status](https://coveralls.io/repos/github/mermaid-js/mermaid/badge.svg?branch=master)](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid) [![NPM](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid) [![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) [![Twitter Follow](https://img.shields.io/badge/Social-mermaidjs__-blue?style=social&logo=twitter)](https://twitter.com/mermaidjs_)
|
||||
|
||||
English | [简体中文](./README.zh-CN.md)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# mermaid
|
||||
|
||||
[![Build CI Status](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml/badge.svg)](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml) [![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.com/package/mermaid) [![npm minified gzipped bundle size](https://img.shields.io/bundlephobia/minzip/mermaid)](https://bundlephobia.com/package/mermaid) [![Coverage Status](https://coveralls.io/repos/github/mermaid-js/mermaid/badge.svg?branch=master)](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid) [![NPM](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid) [![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) [![Twitter Follow](https://img.shields.io/twitter/follow/mermaidjs_?style=social)](https://twitter.com/mermaidjs_)
|
||||
[![Build CI Status](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml/badge.svg)](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml) [![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.com/package/mermaid) [![npm minified gzipped bundle size](https://img.shields.io/bundlephobia/minzip/mermaid)](https://bundlephobia.com/package/mermaid) [![Coverage Status](https://coveralls.io/repos/github/mermaid-js/mermaid/badge.svg?branch=master)](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid) [![NPM](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid) [![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) [![Twitter Follow](https://img.shields.io/badge/Social-mermaidjs__-blue?style=social&logo=twitter)](https://twitter.com/mermaidjs_)
|
||||
|
||||
[English](./README.md) | 简体中文
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
|
||||
**感谢所有参与进来提交 PR,解答疑问的人们! 🙏**
|
||||
|
||||
<a href="https://mermaid-js.github.io/mermaid/landing/"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/img/book-banner-pre-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.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>
|
||||
|
||||
## 关于 Mermaid
|
||||
|
||||
|
10
cSpell.json
10
cSpell.json
@ -6,6 +6,7 @@
|
||||
"adamiecki",
|
||||
"alois",
|
||||
"antiscript",
|
||||
"appli",
|
||||
"applitools",
|
||||
"asciidoctor",
|
||||
"ashish",
|
||||
@ -13,6 +14,7 @@
|
||||
"bbox",
|
||||
"bilkent",
|
||||
"bisheng",
|
||||
"blrs",
|
||||
"braintree",
|
||||
"brkt",
|
||||
"brolin",
|
||||
@ -31,6 +33,7 @@
|
||||
"doku",
|
||||
"dompurify",
|
||||
"edgechromium",
|
||||
"elkjs",
|
||||
"faber",
|
||||
"flatmap",
|
||||
"ftplugin",
|
||||
@ -39,6 +42,7 @@
|
||||
"gitgraph",
|
||||
"globby",
|
||||
"graphlib",
|
||||
"graphviz",
|
||||
"grav",
|
||||
"greywolf",
|
||||
"inkdrop",
|
||||
@ -52,8 +56,10 @@
|
||||
"knut",
|
||||
"laganeckas",
|
||||
"lintstagedrc",
|
||||
"logmsg",
|
||||
"lucida",
|
||||
"matthieu",
|
||||
"mdast",
|
||||
"mdbook",
|
||||
"mermerd",
|
||||
"mindaugas",
|
||||
@ -69,6 +75,7 @@
|
||||
"pnpm",
|
||||
"podlite",
|
||||
"quence",
|
||||
"radious",
|
||||
"ranksep",
|
||||
"rect",
|
||||
"rects",
|
||||
@ -78,17 +85,20 @@
|
||||
"setupgraphviewbox",
|
||||
"shiki",
|
||||
"sidharth",
|
||||
"sidharthv",
|
||||
"sphinxcontrib",
|
||||
"statediagram",
|
||||
"stylis",
|
||||
"substate",
|
||||
"sveidqvist",
|
||||
"swimm",
|
||||
"techn",
|
||||
"teststr",
|
||||
"textlength",
|
||||
"treemap",
|
||||
"ts-nocheck",
|
||||
"tuleap",
|
||||
"ugge",
|
||||
"unist",
|
||||
"verdana",
|
||||
"viewports",
|
||||
|
@ -2,7 +2,7 @@ const utf8ToB64 = (str) => {
|
||||
return window.btoa(unescape(encodeURIComponent(str)));
|
||||
};
|
||||
|
||||
const batchId = 'mermid-batch' + new Date().getTime();
|
||||
const batchId = 'mermaid-batch' + new Date().getTime();
|
||||
|
||||
export const mermaidUrl = (graphStr, options, api) => {
|
||||
const obj = {
|
||||
@ -46,8 +46,22 @@ export const imgSnapshotTest = (graphStr, _options, api = false, validation) =>
|
||||
if (!options.fontSize) {
|
||||
options.fontSize = '16px';
|
||||
}
|
||||
const url = mermaidUrl(graphStr, options, api);
|
||||
openURLAndVerifyRendering(url, options, validation);
|
||||
};
|
||||
|
||||
export const urlSnapshotTest = (url, _options, api = false, validation) => {
|
||||
const options = Object.assign(_options);
|
||||
openURLAndVerifyRendering(url, options, validation);
|
||||
};
|
||||
|
||||
export const renderGraph = (graphStr, options, api) => {
|
||||
const url = mermaidUrl(graphStr, options, api);
|
||||
openURLAndVerifyRendering(url, options);
|
||||
};
|
||||
|
||||
const openURLAndVerifyRendering = (url, options, validation = undefined) => {
|
||||
const useAppli = Cypress.env('useAppli');
|
||||
cy.log('Hello ' + useAppli ? 'Appli' : 'image-snapshot');
|
||||
const name = (options.name || cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
|
||||
|
||||
if (useAppli) {
|
||||
@ -60,82 +74,20 @@ export const imgSnapshotTest = (graphStr, _options, api = false, validation) =>
|
||||
});
|
||||
}
|
||||
|
||||
const url = mermaidUrl(graphStr, options, api);
|
||||
|
||||
cy.visit(url);
|
||||
cy.window().should('have.property', 'rendered', true);
|
||||
cy.get('svg').should('be.visible');
|
||||
|
||||
if (validation) {
|
||||
cy.get('svg').should(validation);
|
||||
}
|
||||
cy.get('svg');
|
||||
// Default name to test title
|
||||
|
||||
if (useAppli) {
|
||||
cy.log('Check eyes' + Cypress.spec.name);
|
||||
cy.eyesCheckWindow('Click!');
|
||||
cy.log('Closing eyes: ' + Cypress.spec.name);
|
||||
cy.log('Closing eyes' + Cypress.spec.name);
|
||||
cy.eyesClose();
|
||||
} else {
|
||||
cy.matchImageSnapshot(name);
|
||||
}
|
||||
};
|
||||
|
||||
export const urlSnapshotTest = (url, _options, api = false, validation) => {
|
||||
cy.log(_options);
|
||||
const options = Object.assign(_options);
|
||||
if (!options.fontFamily) {
|
||||
options.fontFamily = 'courier';
|
||||
}
|
||||
if (!options.sequence) {
|
||||
options.sequence = {};
|
||||
}
|
||||
if (!options.sequence || (options.sequence && !options.sequence.actorFontFamily)) {
|
||||
options.sequence.actorFontFamily = 'courier';
|
||||
}
|
||||
if (options.sequence && !options.sequence.noteFontFamily) {
|
||||
options.sequence.noteFontFamily = 'courier';
|
||||
}
|
||||
options.sequence.actorFontFamily = 'courier';
|
||||
options.sequence.noteFontFamily = 'courier';
|
||||
options.sequence.messageFontFamily = 'courier';
|
||||
if (options.sequence && !options.sequence.actorFontFamily) {
|
||||
options.sequence.actorFontFamily = 'courier';
|
||||
}
|
||||
if (!options.fontSize) {
|
||||
options.fontSize = '16px';
|
||||
}
|
||||
const useAppli = Cypress.env('useAppli');
|
||||
cy.log('Hello ' + useAppli ? 'Appli' : 'image-snapshot');
|
||||
const name = (options.name || cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
|
||||
|
||||
if (useAppli) {
|
||||
cy.log('Opening eyes 2' + Cypress.spec.name);
|
||||
cy.eyesOpen({
|
||||
appName: 'Mermaid',
|
||||
testName: name,
|
||||
batchName: Cypress.spec.name,
|
||||
batchId: batchId + Cypress.spec.name,
|
||||
});
|
||||
}
|
||||
|
||||
cy.visit(url);
|
||||
if (validation) {
|
||||
cy.get('svg').should(validation);
|
||||
}
|
||||
cy.get('body');
|
||||
// Default name to test title
|
||||
|
||||
if (useAppli) {
|
||||
cy.log('Check eyes 2' + Cypress.spec.name);
|
||||
cy.eyesCheckWindow('Click!');
|
||||
cy.log('Closing eyes 2' + Cypress.spec.name);
|
||||
cy.eyesClose();
|
||||
} else {
|
||||
cy.matchImageSnapshot(name);
|
||||
}
|
||||
};
|
||||
|
||||
export const renderGraph = (graphStr, options, api) => {
|
||||
const url = mermaidUrl(graphStr, options, api);
|
||||
|
||||
cy.visit(url);
|
||||
};
|
||||
|
@ -2,8 +2,8 @@ import { urlSnapshotTest } from '../../helpers/util';
|
||||
|
||||
describe('mermaid', () => {
|
||||
describe('registerDiagram', () => {
|
||||
it('should work on @mermaid-js/mermaid-mindmap and mermaid-example-diagram', () => {
|
||||
const url = 'http://localhost:9000/external-diagrams-mindmap.html';
|
||||
it('should work on @mermaid-js/mermaid-example-diagram', () => {
|
||||
const url = 'http://localhost:9000/external-diagrams-example-diagram.html';
|
||||
urlSnapshotTest(url, {}, false, false);
|
||||
});
|
||||
});
|
||||
|
122
cypress/integration/rendering/c4.spec.js
Normal file
122
cypress/integration/rendering/c4.spec.js
Normal file
@ -0,0 +1,122 @@
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util.js';
|
||||
|
||||
describe('C4 diagram', () => {
|
||||
it('should render a simple C4Context diagram', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
C4Context
|
||||
accTitle: C4 context demo
|
||||
accDescr: Many large C4 diagrams
|
||||
|
||||
title System Context diagram for Internet Banking System
|
||||
|
||||
Enterprise_Boundary(b0, "BankBoundary0") {
|
||||
Person(customerA, "Banking Customer A", "A customer of the bank, with personal bank accounts.")
|
||||
|
||||
System(SystemAA, "Internet Banking System", "Allows customers to view information about their bank accounts, and make payments.")
|
||||
|
||||
Enterprise_Boundary(b1, "BankBoundary") {
|
||||
System_Ext(SystemC, "E-mail system", "The internal Microsoft Exchange e-mail system.")
|
||||
}
|
||||
}
|
||||
|
||||
BiRel(customerA, SystemAA, "Uses")
|
||||
Rel(SystemAA, SystemC, "Sends e-mails", "SMTP")
|
||||
Rel(SystemC, customerA, "Sends e-mails to")
|
||||
|
||||
UpdateElementStyle(customerA, $fontColor="red", $bgColor="grey", $borderColor="red")
|
||||
UpdateRelStyle(customerA, SystemAA, $textColor="blue", $lineColor="blue", $offsetX="5")
|
||||
UpdateRelStyle(SystemC, customerA, $textColor="red", $lineColor="red", $offsetX="-50", $offsetY="20")
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a simple C4Container diagram', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
C4Container
|
||||
title Container diagram for Internet Banking System
|
||||
|
||||
System_Ext(email_system, "E-Mail System", "The internal Microsoft Exchange system", $tags="v1.0")
|
||||
Person(customer, Customer, "A customer of the bank, with personal bank accounts", $tags="v1.0")
|
||||
|
||||
Container_Boundary(c1, "Internet Banking") {
|
||||
Container(spa, "Single-Page App", "JavaScript, Angular", "Provides all the Internet banking functionality to customers via their web browser")
|
||||
}
|
||||
|
||||
Rel(customer, spa, "Uses", "HTTPS")
|
||||
Rel(email_system, customer, "Sends e-mails to")
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a simple C4Component diagram', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
C4Component
|
||||
title Component diagram for Internet Banking System - API Application
|
||||
|
||||
Container(spa, "Single Page Application", "javascript and angular", "Provides all the internet banking functionality to customers via their web browser.")
|
||||
|
||||
Container_Boundary(api, "API Application") {
|
||||
Component(sign, "Sign In Controller", "MVC Rest Controller", "Allows users to sign in to the internet banking system")
|
||||
}
|
||||
|
||||
Rel_Back(spa, sign, "Uses", "JSON/HTTPS")
|
||||
UpdateRelStyle(spa, sign, $offsetY="-40")
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a simple C4Dynamic diagram', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
C4Dynamic
|
||||
title Dynamic diagram for Internet Banking System - API Application
|
||||
|
||||
ContainerDb(c4, "Database", "Relational Database Schema", "Stores user registration information, hashed authentication credentials, access logs, etc.")
|
||||
Container(c1, "Single-Page Application", "JavaScript and Angular", "Provides all of the Internet banking functionality to customers via their web browser.")
|
||||
Container_Boundary(b, "API Application") {
|
||||
Component(c3, "Security Component", "Spring Bean", "Provides functionality Related to signing in, changing passwords, etc.")
|
||||
Component(c2, "Sign In Controller", "Spring MVC Rest Controller", "Allows users to sign in to the Internet Banking System.")
|
||||
}
|
||||
Rel(c1, c2, "Submits credentials to", "JSON/HTTPS")
|
||||
Rel(c2, c3, "Calls isAuthenticated() on")
|
||||
Rel(c3, c4, "select * from users where username = ?", "JDBC")
|
||||
|
||||
UpdateRelStyle(c1, c2, $textColor="red", $offsetY="-40")
|
||||
UpdateRelStyle(c2, c3, $textColor="red", $offsetX="-40", $offsetY="60")
|
||||
UpdateRelStyle(c3, c4, $textColor="red", $offsetY="-40", $offsetX="10")
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a simple C4Deployment diagram', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
C4Deployment
|
||||
title Deployment Diagram for Internet Banking System - Live
|
||||
|
||||
Deployment_Node(mob, "Customer's mobile device", "Apple IOS or Android"){
|
||||
Container(mobile, "Mobile App", "Xamarin", "Provides a limited subset of the Internet Banking functionality to customers via their mobile device.")
|
||||
}
|
||||
|
||||
Deployment_Node(plc, "Big Bank plc", "Big Bank plc data center"){
|
||||
Deployment_Node(dn, "bigbank-api*** x8", "Ubuntu 16.04 LTS"){
|
||||
Deployment_Node(apache, "Apache Tomcat", "Apache Tomcat 8.x"){
|
||||
Container(api, "API Application", "Java and Spring MVC", "Provides Internet Banking functionality via a JSON/HTTPS API.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rel(mobile, api, "Makes API calls to", "json/HTTPS")
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
});
|
@ -182,6 +182,20 @@ describe('Entity Relationship Diagram', () => {
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('should render entities with length in attributes type', () => {
|
||||
renderGraph(
|
||||
`
|
||||
erDiagram
|
||||
CLUSTER {
|
||||
varchar(99) name
|
||||
string(255) description
|
||||
}
|
||||
`,
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('should render entities and attributes with big and small entity names', () => {
|
||||
renderGraph(
|
||||
`
|
||||
|
687
cypress/integration/rendering/flowchart-elk.spec.js
Normal file
687
cypress/integration/rendering/flowchart-elk.spec.js
Normal file
@ -0,0 +1,687 @@
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util';
|
||||
|
||||
describe('Flowchart ELK', () => {
|
||||
it('1-elk: should render a simple flowchart', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart-elk TD
|
||||
A[Christmas] -->|Get money| B(Go shopping)
|
||||
B --> C{Let me think}
|
||||
C -->|One| D[Laptop]
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
imgSnapshotTest(
|
||||
`flowchart TD
|
||||
A[Christmas] -->|Get money| B(Go shopping)
|
||||
B --> C{Let me think}
|
||||
C -->|One| D[Laptop]
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
`,
|
||||
{ flowchart: { defaultRenderer: 'elk' } }
|
||||
);
|
||||
});
|
||||
|
||||
it('2-elk: should render a simple flowchart with diagramPadding set to 0', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart-elk TD
|
||||
A[Christmas] -->|Get money| B(Go shopping)
|
||||
B --> C{Let me think}
|
||||
%% this is a comment
|
||||
C -->|One| D[Laptop]
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
`,
|
||||
{ flowchart: { diagramPadding: 0 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('3-elk: a link with correct arrowhead to a subgraph', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart-elk TD
|
||||
P1
|
||||
P1 -->P1.5
|
||||
subgraph P1.5
|
||||
P2
|
||||
P2.5(( A ))
|
||||
P3
|
||||
end
|
||||
P2 --> P4
|
||||
P3 --> P6
|
||||
P1.5 --> P5
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('4-elk: Length of edges', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart-elk TD
|
||||
L1 --- L2
|
||||
L2 --- C
|
||||
M1 ---> C
|
||||
R1 .-> R2
|
||||
R2 <.-> C
|
||||
C -->|Label 1| E1
|
||||
C <-- Label 2 ---> E2
|
||||
C ----> E3
|
||||
C <-...-> E4
|
||||
C ======> E5
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('5-elk: should render escaped without html labels', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart-elk TD
|
||||
a["<strong>Haiya</strong>"]---->b
|
||||
`,
|
||||
{ htmlLabels: false, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
});
|
||||
it('6-elk: should render non-escaped with html labels', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart-elk TD
|
||||
a["<strong>Haiya</strong>"]===>b
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('7-elk: should render a flowchart when useMaxWidth is true (default)', () => {
|
||||
renderGraph(
|
||||
`flowchart-elk TD
|
||||
A[Christmas] -->|Get money| B(Go shopping)
|
||||
B --> C{Let me think}
|
||||
C -->|One| D[Laptop]
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
`,
|
||||
{ flowchart: { useMaxWidth: true } }
|
||||
);
|
||||
cy.get('svg').should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
// expect(svg).to.have.attr('height');
|
||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||
// const height = parseFloat(svg.attr('height'));
|
||||
// expect(height).to.be.within(446 * 0.95, 446 * 1.05);
|
||||
const style = svg.attr('style');
|
||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
||||
expect(maxWidthValue).to.be.within(230 * 0.95, 230 * 1.05);
|
||||
});
|
||||
});
|
||||
it('8-elk: should render a flowchart when useMaxWidth is false', () => {
|
||||
renderGraph(
|
||||
`flowchart-elk TD
|
||||
A[Christmas] -->|Get money| B(Go shopping)
|
||||
B --> C{Let me think}
|
||||
C -->|One| D[Laptop]
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
`,
|
||||
{ flowchart: { useMaxWidth: false } }
|
||||
);
|
||||
cy.get('svg').should((svg) => {
|
||||
// const height = parseFloat(svg.attr('height'));
|
||||
const width = parseFloat(svg.attr('width'));
|
||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||
// expect(height).to.be.within(446 * 0.95, 446 * 1.05);
|
||||
expect(width).to.be.within(230 * 0.95, 230 * 1.05);
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
});
|
||||
|
||||
it('V2 elk - 16: Render Stadium shape', () => {
|
||||
imgSnapshotTest(
|
||||
` flowchart-elk TD
|
||||
A([stadium shape test])
|
||||
A -->|Get money| B([Go shopping])
|
||||
B --> C([Let me think...<br />Do I want something for work,<br />something to spend every free second with,<br />or something to get around?])
|
||||
C -->|One| D([Laptop])
|
||||
C -->|Two| E([iPhone])
|
||||
C -->|Three| F([Car<br/>wroom wroom])
|
||||
click A "index.html#link-clicked" "link test"
|
||||
click B testClick "click test"
|
||||
classDef someclass fill:#f96;
|
||||
class A someclass;
|
||||
class C someclass;
|
||||
`,
|
||||
{ flowchart: { htmlLabels: false }, fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
it('50-elk: handle nested subgraphs in reverse order', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart-elk LR
|
||||
a -->b
|
||||
subgraph A
|
||||
B
|
||||
end
|
||||
subgraph B
|
||||
b
|
||||
end
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
|
||||
it('51-elk: handle nested subgraphs in reverse order', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart-elk LR
|
||||
a -->b
|
||||
subgraph A
|
||||
B
|
||||
end
|
||||
subgraph B
|
||||
b
|
||||
end
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
|
||||
it('52-elk: handle nested subgraphs in several levels', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart-elk TB
|
||||
b-->B
|
||||
a-->c
|
||||
subgraph O
|
||||
A
|
||||
end
|
||||
subgraph B
|
||||
c
|
||||
end
|
||||
subgraph A
|
||||
a
|
||||
b
|
||||
B
|
||||
end
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
|
||||
it('53-elk: handle nested subgraphs with edges in and out', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart-elk TB
|
||||
internet
|
||||
nat
|
||||
routeur
|
||||
lb1
|
||||
lb2
|
||||
compute1
|
||||
compute2
|
||||
subgraph project
|
||||
routeur
|
||||
nat
|
||||
subgraph subnet1
|
||||
compute1
|
||||
lb1
|
||||
end
|
||||
subgraph subnet2
|
||||
compute2
|
||||
lb2
|
||||
end
|
||||
end
|
||||
internet --> routeur
|
||||
routeur --> subnet1 & subnet2
|
||||
subnet1 & subnet2 --> nat --> internet
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
|
||||
it('54-elk: handle nested subgraphs with outgoing links', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart-elk TD
|
||||
subgraph main
|
||||
subgraph subcontainer
|
||||
subcontainer-child
|
||||
end
|
||||
subcontainer-child--> subcontainer-sibling
|
||||
end
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
|
||||
it('55-elk: handle nested subgraphs with outgoing links 2', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart-elk TD
|
||||
|
||||
subgraph one[One]
|
||||
subgraph sub_one[Sub One]
|
||||
_sub_one
|
||||
end
|
||||
subgraph sub_two[Sub Two]
|
||||
_sub_two
|
||||
end
|
||||
_one
|
||||
end
|
||||
|
||||
%% here, either the first or the second one
|
||||
sub_one --> sub_two
|
||||
_one --> b
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
|
||||
it('56-elk: handle nested subgraphs with outgoing links 3', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart-elk TB
|
||||
subgraph container_Beta
|
||||
process_C-->Process_D
|
||||
end
|
||||
subgraph container_Alpha
|
||||
process_A-->process_B
|
||||
process_A-->|messages|process_C
|
||||
end
|
||||
process_B-->|via_AWSBatch|container_Beta
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('57-elk: handle nested subgraphs with outgoing links 4', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart-elk LR
|
||||
subgraph A
|
||||
a -->b
|
||||
end
|
||||
subgraph B
|
||||
b
|
||||
end
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
|
||||
it('57-elk: handle nested subgraphs with outgoing links 2', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart-elk TB
|
||||
c1-->a2
|
||||
subgraph one
|
||||
a1-->a2
|
||||
end
|
||||
subgraph two
|
||||
b1-->b2
|
||||
end
|
||||
subgraph three
|
||||
c1-->c2
|
||||
end
|
||||
one --> two
|
||||
three --> two
|
||||
two --> c2
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('57.x: handle nested subgraphs with outgoing links 5', () => {
|
||||
imgSnapshotTest(
|
||||
`%% this does not produce the desired result
|
||||
flowchart-elk TB
|
||||
subgraph container_Beta
|
||||
process_C-->Process_D
|
||||
end
|
||||
subgraph container_Alpha
|
||||
process_A-->process_B
|
||||
process_B-->|via_AWSBatch|container_Beta
|
||||
process_A-->|messages|process_C
|
||||
end
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('58-elk: handle styling with style expressions', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart-elk LR
|
||||
id1(Start)-->id2(Stop)
|
||||
style id1 fill:#f9f,stroke:#333,stroke-width:4px
|
||||
style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('59-elk: handle styling of subgraphs and links', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart-elk TD
|
||||
A[Christmas] ==> D
|
||||
A[Christmas] -->|Get money| B(Go shopping)
|
||||
A[Christmas] ==> C
|
||||
subgraph T ["Test"]
|
||||
A
|
||||
B
|
||||
C
|
||||
end
|
||||
|
||||
classDef Test fill:#F84E68,stroke:#333,color:white;
|
||||
class A,T Test
|
||||
classDef TestSub fill:green;
|
||||
class T TestSub
|
||||
linkStyle 0,1 color:orange, stroke: orange;
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('60-elk: handle styling for all node shapes - v2', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart-elk LR
|
||||
A[red text] -->|default style| B(blue text)
|
||||
C([red text]) -->|default style| D[[blue text]]
|
||||
E[(red text)] -->|default style| F((blue text))
|
||||
G>red text] -->|default style| H{blue text}
|
||||
I{{red text}} -->|default style| J[/blue text/]
|
||||
K[\\ red text\\] -->|default style| L[/blue text\\]
|
||||
M[\\ red text/] -->|default style| N[blue text];
|
||||
O(((red text))) -->|default style| P(((blue text)));
|
||||
linkStyle default color:Sienna;
|
||||
style A stroke:#ff0000,fill:#ffcccc,color:#ff0000;
|
||||
style B stroke:#0000ff,fill:#ccccff,color:#0000ff;
|
||||
style C stroke:#ff0000,fill:#ffcccc,color:#ff0000;
|
||||
style D stroke:#0000ff,fill:#ccccff,color:#0000ff;
|
||||
style E stroke:#ff0000,fill:#ffcccc,color:#ff0000;
|
||||
style F stroke:#0000ff,fill:#ccccff,color:#0000ff;
|
||||
style G stroke:#ff0000,fill:#ffcccc,color:#ff0000;
|
||||
style H stroke:#0000ff,fill:#ccccff,color:#0000ff;
|
||||
style I stroke:#ff0000,fill:#ffcccc,color:#ff0000;
|
||||
style J stroke:#0000ff,fill:#ccccff,color:#0000ff;
|
||||
style K stroke:#ff0000,fill:#ffcccc,color:#ff0000;
|
||||
style L stroke:#0000ff,fill:#ccccff,color:#0000ff;
|
||||
style M stroke:#ff0000,fill:#ffcccc,color:#ff0000;
|
||||
style N stroke:#0000ff,fill:#ccccff,color:#0000ff;
|
||||
style O stroke:#ff0000,fill:#ffcccc,color:#ff0000;
|
||||
style P stroke:#0000ff,fill:#ccccff,color:#0000ff;
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose', logLevel: 2 }
|
||||
);
|
||||
});
|
||||
it('61-elk: fontawesome icons in edge labels', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart-elk TD
|
||||
C -->|fa:fa-car Car| F[fa:fa-car Car]
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('62-elk: should render styled subgraphs', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart-elk TB
|
||||
A
|
||||
B
|
||||
subgraph foo[Foo SubGraph]
|
||||
C
|
||||
D
|
||||
end
|
||||
subgraph bar[Bar SubGraph]
|
||||
E
|
||||
F
|
||||
end
|
||||
G
|
||||
|
||||
A-->B
|
||||
B-->C
|
||||
C-->D
|
||||
B-->D
|
||||
D-->E
|
||||
E-->A
|
||||
E-->F
|
||||
F-->D
|
||||
F-->G
|
||||
B-->G
|
||||
G-->D
|
||||
|
||||
style foo fill:#F99,stroke-width:2px,stroke:#F0F,color:darkred
|
||||
style bar fill:#999,stroke-width:10px,stroke:#0F0,color:blue
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('63-elk: title on subgraphs should be themable', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
%%{init:{"theme":"base", "themeVariables": {"primaryColor":"#411d4e", "titleColor":"white", "darkMode":true}}}%%
|
||||
flowchart-elk LR
|
||||
subgraph A
|
||||
a --> b
|
||||
end
|
||||
subgraph B
|
||||
i -->f
|
||||
end
|
||||
A --> B
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('65-elk: text-color from classes', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart-elk LR
|
||||
classDef dark fill:#000,stroke:#000,stroke-width:4px,color:#fff
|
||||
Lorem --> Ipsum --> Dolor
|
||||
class Lorem,Dolor dark
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('66-elk: More nested subgraph cases (TB)', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart-elk TB
|
||||
subgraph two
|
||||
b1
|
||||
end
|
||||
subgraph three
|
||||
c2
|
||||
end
|
||||
|
||||
three --> two
|
||||
two --> c2
|
||||
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('67-elk: More nested subgraph cases (RL)', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart-elk RL
|
||||
subgraph two
|
||||
b1
|
||||
end
|
||||
subgraph three
|
||||
c2
|
||||
end
|
||||
|
||||
three --> two
|
||||
two --> c2
|
||||
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('68-elk: More nested subgraph cases (BT)', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart-elk BT
|
||||
subgraph two
|
||||
b1
|
||||
end
|
||||
subgraph three
|
||||
c2
|
||||
end
|
||||
|
||||
three --> two
|
||||
two --> c2
|
||||
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('69-elk: More nested subgraph cases (LR)', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart-elk LR
|
||||
subgraph two
|
||||
b1
|
||||
end
|
||||
subgraph three
|
||||
c2
|
||||
end
|
||||
|
||||
three --> two
|
||||
two --> c2
|
||||
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('70-elk: Handle nested subgraph cases (TB) link out and link between subgraphs', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart-elk TB
|
||||
subgraph S1
|
||||
sub1 -->sub2
|
||||
end
|
||||
subgraph S2
|
||||
sub4
|
||||
end
|
||||
S1 --> S2
|
||||
sub1 --> sub4
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('71-elk: Handle nested subgraph cases (RL) link out and link between subgraphs', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart-elk RL
|
||||
subgraph S1
|
||||
sub1 -->sub2
|
||||
end
|
||||
subgraph S2
|
||||
sub4
|
||||
end
|
||||
S1 --> S2
|
||||
sub1 --> sub4
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('72-elk: Handle nested subgraph cases (BT) link out and link between subgraphs', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart-elk BT
|
||||
subgraph S1
|
||||
sub1 -->sub2
|
||||
end
|
||||
subgraph S2
|
||||
sub4
|
||||
end
|
||||
S1 --> S2
|
||||
sub1 --> sub4
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('74-elk: Handle nested subgraph cases (RL) link out and link between subgraphs', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart-elk RL
|
||||
subgraph S1
|
||||
sub1 -->sub2
|
||||
end
|
||||
subgraph S2
|
||||
sub4
|
||||
end
|
||||
S1 --> S2
|
||||
sub1 --> sub4
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('74-elk: Handle labels for multiple edges from and to the same couple of nodes', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart-elk RL
|
||||
subgraph one
|
||||
a1 -- l1 --> a2
|
||||
a1 -- l2 --> a2
|
||||
end
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
|
||||
it('76-elk: handle unicode encoded character with HTML labels true', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart-elk TB
|
||||
a{{"Lorem 'ipsum' dolor 'sit' amet, 'consectetur' adipiscing 'elit'."}}
|
||||
--> b{{"Lorem #quot;ipsum#quot; dolor #quot;sit#quot; amet,#quot;consectetur#quot; adipiscing #quot;elit#quot;."}}
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
|
||||
it('2050-elk: handling of different rendering direction in subgraphs', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart-elk LR
|
||||
|
||||
subgraph TOP
|
||||
direction TB
|
||||
subgraph B1
|
||||
direction RL
|
||||
i1 -->f1
|
||||
end
|
||||
subgraph B2
|
||||
direction BT
|
||||
i2 -->f2
|
||||
end
|
||||
end
|
||||
A --> TOP --> B
|
||||
B1 --> B2
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
|
||||
it('2388-elk: handling default in the node name', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart-elk LR
|
||||
default-index.js --> dot.template.js
|
||||
index.js --> module-utl.js
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('2824-elk: Clipping of edges', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart-elk TD
|
||||
A --> B
|
||||
A --> C
|
||||
B --> C
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('1433-elk: should render a titled flowchart with titleTopMargin set to 0', () => {
|
||||
imgSnapshotTest(
|
||||
`---
|
||||
title: Simple flowchart
|
||||
---
|
||||
flowchart-elk TD
|
||||
A --> B
|
||||
`,
|
||||
{ titleTopMargin: 0 }
|
||||
);
|
||||
});
|
||||
});
|
@ -1,4 +1,4 @@
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util.js';
|
||||
import { imgSnapshotTest } from '../../helpers/util.js';
|
||||
|
||||
/**
|
||||
* Check whether the SVG Element has a Mindmap root
|
||||
@ -158,7 +158,6 @@ mindmap
|
||||
undefined,
|
||||
shouldHaveRoot
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('rounded rect shape', () => {
|
||||
imgSnapshotTest(
|
||||
@ -172,7 +171,6 @@ mindmap
|
||||
undefined,
|
||||
shouldHaveRoot
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('circle shape', () => {
|
||||
imgSnapshotTest(
|
||||
@ -186,7 +184,6 @@ mindmap
|
||||
undefined,
|
||||
shouldHaveRoot
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('default shape', () => {
|
||||
imgSnapshotTest(
|
||||
@ -198,7 +195,6 @@ mindmap
|
||||
undefined,
|
||||
shouldHaveRoot
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('adding children', () => {
|
||||
imgSnapshotTest(
|
||||
@ -212,7 +208,6 @@ mindmap
|
||||
undefined,
|
||||
shouldHaveRoot
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('adding grand children', () => {
|
||||
imgSnapshotTest(
|
||||
@ -227,7 +222,6 @@ mindmap
|
||||
undefined,
|
||||
shouldHaveRoot
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
/* The end */
|
||||
});
|
||||
|
@ -3,6 +3,42 @@
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util';
|
||||
|
||||
context('Sequence diagram', () => {
|
||||
it('should render a sequence diagram with boxes', () => {
|
||||
renderGraph(
|
||||
`
|
||||
sequenceDiagram
|
||||
box LightGrey Alice and Bob
|
||||
participant Alice
|
||||
participant Bob
|
||||
end
|
||||
participant John as John<br/>Second Line
|
||||
Alice ->> Bob: Hello Bob, how are you?
|
||||
Bob-->>John: How about you John?
|
||||
Bob--x Alice: I am good thanks!
|
||||
Bob-x John: I am good thanks!
|
||||
Note right of John: Bob thinks a long<br/>long time, so long<br/>that the text does<br/>not fit on a row.
|
||||
Bob-->Alice: Checking with John...
|
||||
alt either this
|
||||
Alice->>John: Yes
|
||||
else or this
|
||||
Alice->>John: No
|
||||
else or this will happen
|
||||
Alice->John: Maybe
|
||||
end
|
||||
par this happens in parallel
|
||||
Alice -->> Bob: Parallel message 1
|
||||
and
|
||||
Alice -->> John: Parallel message 2
|
||||
end
|
||||
`,
|
||||
{ sequence: { useMaxWidth: false } }
|
||||
);
|
||||
cy.get('svg').should((svg) => {
|
||||
const width = parseFloat(svg.attr('width'));
|
||||
expect(width).to.be.within(830 * 0.95, 830 * 1.05);
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
});
|
||||
it('should render a simple sequence diagram', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
|
164
cypress/integration/rendering/timeline.spec.ts
Normal file
164
cypress/integration/rendering/timeline.spec.ts
Normal file
@ -0,0 +1,164 @@
|
||||
import { imgSnapshotTest } from '../../helpers/util.js';
|
||||
|
||||
describe('Timeline diagram', () => {
|
||||
it('1: should render a simple timeline with no specific sections', () => {
|
||||
imgSnapshotTest(
|
||||
`timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('2: should render a timeline diagram with sections', () => {
|
||||
imgSnapshotTest(
|
||||
`timeline
|
||||
title Timeline of Industrial Revolution
|
||||
section 17th-20th century
|
||||
Industry 1.0 : Machinery, Water power, Steam <br>power
|
||||
Industry 2.0 : Electricity, Internal combustion engine, Mass production
|
||||
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
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('3: should render a complex timeline with sections, and long events text with <br>', () => {
|
||||
imgSnapshotTest(
|
||||
`timeline
|
||||
title England's History Timeline
|
||||
section Stone Age
|
||||
7600 BC : Britain's oldest known house was built in Orkney, Scotland
|
||||
6000 BC : Sea levels rise and Britain becomes an island.<br> The people who live here are hunter-gatherers.
|
||||
section Broze Age
|
||||
2300 BC : People arrive from Europe and settle in Britain. <br>They bring farming and metalworking.
|
||||
: New styles of pottery and ways of burying the dead appear.
|
||||
2200 BC : The last major building works are completed at Stonehenge.<br> People now bury their dead in stone circles.
|
||||
: The first metal objects are made in Britain.Some other nice things happen. it is a good time to be alive.
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('4: should render a simple timeline with directives and disableMultiColor:true ', () => {
|
||||
imgSnapshotTest(
|
||||
`%%{init: { 'logLevel': 'debug', 'theme': 'base', 'timeline': {'disableMulticolor': true}}}%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('5: should render a simple timeline with directive overriden colors', () => {
|
||||
imgSnapshotTest(
|
||||
` %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': {
|
||||
'cScale0': '#ff0000',
|
||||
'cScale1': '#00ff00',
|
||||
'cScale2': '#0000ff'
|
||||
} } }%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
2007 : Tumblr
|
||||
2008 : Instagram
|
||||
2010 : Pinterest
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('6: should render a simple timeline in base theme', () => {
|
||||
imgSnapshotTest(
|
||||
`%%{init: { 'logLevel': 'debug', 'theme': 'base' } }%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
2007 : Tumblr
|
||||
2008 : Instagram
|
||||
2010 : Pinterest
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('7: should render a simple timeline in default theme', () => {
|
||||
imgSnapshotTest(
|
||||
`%%{init: { 'logLevel': 'debug', 'theme': 'default' } }%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
2007 : Tumblr
|
||||
2008 : Instagram
|
||||
2010 : Pinterest
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('8: should render a simple timeline in dark theme', () => {
|
||||
imgSnapshotTest(
|
||||
`%%{init: { 'logLevel': 'debug', 'theme': 'dark' } }%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
2007 : Tumblr
|
||||
2008 : Instagram
|
||||
2010 : Pinterest
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('9: should render a simple timeline in neutral theme', () => {
|
||||
imgSnapshotTest(
|
||||
`%%{init: { 'logLevel': 'debug', 'theme': 'neutral' } }%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
2007 : Tumblr
|
||||
2008 : Instagram
|
||||
2010 : Pinterest
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('10: should render a simple timeline in forest theme', () => {
|
||||
imgSnapshotTest(
|
||||
`%%{init: { 'logLevel': 'debug', 'theme': 'forest' } }%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
2007 : Tumblr
|
||||
2008 : Instagram
|
||||
2010 : Pinterest
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
});
|
231
cypress/platform/ashish2.html
Normal file
231
cypress/platform/ashish2.html
Normal file
@ -0,0 +1,231 @@
|
||||
<html>
|
||||
<head>
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<style>
|
||||
body {
|
||||
/* background: rgb(221, 208, 208); */
|
||||
/* background:#333; */
|
||||
font-family: 'Arial';
|
||||
/* font-size: 18px !important; */
|
||||
}
|
||||
h1 {
|
||||
color: grey;
|
||||
}
|
||||
.mermaid2 {
|
||||
display: none;
|
||||
}
|
||||
.mermaid svg {
|
||||
/* font-size: 18px !important; */
|
||||
background-color: #eee;
|
||||
background-image: radial-gradient(#fff 1%, transparent 11%),
|
||||
radial-gradient(#fff 1%, transparent 11%);
|
||||
background-size: 20px 20px;
|
||||
background-position: 0 0, 10px 10px;
|
||||
background-repeat: repeat;
|
||||
}
|
||||
.malware {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 150px;
|
||||
background: red;
|
||||
color: black;
|
||||
display: flex;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: monospace;
|
||||
font-size: 72px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div>Security check</div>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
timeline
|
||||
title My day
|
||||
section section with no tasks
|
||||
section Go to work at the dog office
|
||||
1930 : first step : second step is a long step
|
||||
: third step
|
||||
1940 : fourth step : fifth step
|
||||
section Go home
|
||||
1950 : India got independent and already won war against Pakistan
|
||||
1960 : India fights poverty, looses war to China and gets nuclear weapons from USA and USSR
|
||||
1970 : Green Revolution comes to india
|
||||
section Another section with no tasks
|
||||
I am a big big big tasks
|
||||
I am not so big tasks
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
timeline
|
||||
title MermaidChart 2023 Timeline
|
||||
section 2023 Q1 <br> Release Personal Tier
|
||||
Buttet 1 : sub-point 1a : sub-point 1b
|
||||
: sub-point 1c
|
||||
Bullet 2 : sub-point 2a : sub-point 2b
|
||||
section 2023 Q2 <br> Release XYZ Tier
|
||||
Buttet 3 : sub-point <br> 3a : sub-point 3b
|
||||
: sub-point 3c
|
||||
Bullet 4 : sub-point 4a : sub-point 4b
|
||||
|
||||
</pre>
|
||||
|
||||
<pre id="diagram" class="mermaid">
|
||||
timeline
|
||||
title England's History Timeline
|
||||
section Stone Age
|
||||
7600 BC : Britain's oldest known house was built in Orkney, Scotland
|
||||
6000 BC : Sea levels rise and Britain becomes an island. The people who live here are hunter-gatherers.
|
||||
section Broze Age
|
||||
2300 BC : People arrive from Europe and settle in Britain. They bring farming and metalworking.
|
||||
: New styles of pottery and ways of burying the dead appear.
|
||||
2200 BC : The last major building works are completed at Stonehenge. People now bury their dead in stone circles.
|
||||
: The first metal objects are made in Britain.Some other nice things happen. it is a good time to be alive.
|
||||
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
%%{'init': { 'logLevel': 'debug', 'theme': 'default', 'timeline': {'disableMulticolor':false} } }%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google : Pixar
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
2007 : Tumblr
|
||||
2008s : Instagram
|
||||
2010 : Pinterest
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'base', 'themeVariables': {
|
||||
'cScale0': '#ff0000',
|
||||
'cScale1': '#00ff00',
|
||||
'cScale2': '#ff0000'
|
||||
} } }%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google : Pixar
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
2007 : Tumblr
|
||||
2008s : Instagram
|
||||
2010 : Pinterest
|
||||
</pre>
|
||||
|
||||
<pre id="diagram" class="mermaid2">
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': {
|
||||
'cScale0': '#ff0000',
|
||||
'cScale1': '#00ff00',
|
||||
'cScale2': '#0000ff'
|
||||
} } }%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
2007 : Tumblr
|
||||
2008 : Instagram
|
||||
2010 : Pinterest
|
||||
|
||||
</pre>
|
||||
|
||||
<pre id="diagram" class="mermaid2">
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
2007 : Tumblr
|
||||
2008s : Instagram
|
||||
2010 : Pinterest
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
mindmap
|
||||
root
|
||||
child1((Circle))
|
||||
grandchild 1
|
||||
grandchild 2
|
||||
child2(Round rectangle)
|
||||
grandchild 3
|
||||
grandchild 4
|
||||
child3[Square]
|
||||
grandchild 5
|
||||
::icon(mdi mdi-fire)
|
||||
gc6((grand<br/>child 6))
|
||||
::icon(mdi mdi-fire)
|
||||
gc7((grand<br/>grand<br/>child 8))
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
flowchart-elk TB
|
||||
a --> b
|
||||
a --> c
|
||||
b --> d
|
||||
c --> d
|
||||
</pre>
|
||||
|
||||
<!-- <div id="cy"></div> -->
|
||||
<!-- <script src="http://localhost:9000/packages/mermaid-mindmap/dist/mermaid-mindmap-detector.js"></script> -->
|
||||
<!-- <script src="./mermaid-example-diagram-detector.js"></script> -->
|
||||
<!-- <script src="//cdn.jsdelivr.net/npm/mermaid@9.1.7/dist/mermaid.min.js"></script> -->
|
||||
<script type="module">
|
||||
//import mindmap from '../../packages/mermaid-mindmap/src/detector';
|
||||
// import example from '../../packages/mermaid-example-diagram/src/detector';
|
||||
// import timeline from '../../packages/mermaid-timeline/src/detector';
|
||||
import mermaid from '../../packages/mermaid/src/mermaid';
|
||||
// await mermaid.registerExternalDiagrams([]);
|
||||
mermaid.parseError = function (err, hash) {
|
||||
// console.error('Mermaid error: ', err);
|
||||
};
|
||||
mermaid.initialize({
|
||||
theme: 'base',
|
||||
startOnLoad: true,
|
||||
logLevel: 0,
|
||||
flowchart: {
|
||||
useMaxWidth: false,
|
||||
htmlLabels: true,
|
||||
},
|
||||
gantt: {
|
||||
useMaxWidth: false,
|
||||
},
|
||||
timeline: {
|
||||
disableMulticolor: false,
|
||||
htmlLabels: false,
|
||||
},
|
||||
useMaxWidth: true,
|
||||
lazyLoadedDiagrams: [
|
||||
// './mermaid-mindmap-detector.esm.mjs',
|
||||
// './mermaid-example-diagram-detector.esm.mjs',
|
||||
//'./mermaid-timeline-detector.esm.mjs',
|
||||
],
|
||||
});
|
||||
function callback() {
|
||||
alert('It worked');
|
||||
}
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('In parse error:');
|
||||
console.error(err);
|
||||
};
|
||||
// mermaid.test1('first_slow', 1200).then((r) => console.info(r));
|
||||
// mermaid.test1('second_fast', 200).then((r) => console.info(r));
|
||||
// mermaid.test1('third_fast', 200).then((r) => console.info(r));
|
||||
// mermaid.test1('forth_slow', 1200).then((r) => console.info(r));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -46,13 +46,9 @@
|
||||
<pre class="mermaid" style="width: 100%; height: 20%">
|
||||
%%{init: {'theme': 'base', 'fontFamily': 'courier', 'themeVariables': { 'primaryColor': '#fff000'}}}%%
|
||||
classDiagram-v2
|
||||
class BankAccount{
|
||||
+String owner
|
||||
+BigDecimal balance
|
||||
+deposit(amount) bool
|
||||
+withdrawl(amount) int
|
||||
}
|
||||
cssClass "BankAccount" customCss
|
||||
classA <|-- classB : implements
|
||||
classC *-- classD : composition
|
||||
classE o-- classF : aggregation
|
||||
</pre>
|
||||
<pre class="mermaid2" style="width: 100%; height: 20%">
|
||||
%%{init: {'theme': 'base', 'fontFamily': 'courier', 'themeVariables': { 'primaryColor': '#fff000'}}}%%
|
||||
|
@ -2,34 +2,8 @@
|
||||
<body>
|
||||
<h1>Should correctly load a third-party diagram using registerDiagram</h1>
|
||||
<pre id="diagram" class="mermaid">
|
||||
mindmap
|
||||
root
|
||||
A
|
||||
B
|
||||
C
|
||||
D
|
||||
E
|
||||
A2
|
||||
B2
|
||||
C2
|
||||
D2
|
||||
E2
|
||||
child1((Circle))
|
||||
grandchild 1
|
||||
grandchild 2
|
||||
child2(Round rectangle)
|
||||
grandchild 3
|
||||
grandchild 4
|
||||
child3[Square]
|
||||
grandchild 5
|
||||
::icon(mdi mdi-fire)
|
||||
gc6((grand<br/>child 6))
|
||||
::icon(mdi mdi-fire)
|
||||
gc7((grand<br/>grand<br/>child 8))
|
||||
example-diagram
|
||||
</pre>
|
||||
<!-- <pre id="diagram" class="mermaid2">
|
||||
example-diagram
|
||||
</pre> -->
|
||||
|
||||
<!-- <div id="cy"></div> -->
|
||||
<!-- <script src="http://localhost:9000/packages/mermaid-mindmap/dist/mermaid-mindmap-detector.js"></script> -->
|
||||
@ -37,13 +11,16 @@ mindmap
|
||||
<!-- <script src="//cdn.jsdelivr.net/npm/mermaid@9.1.7/dist/mermaid.min.js"></script> -->
|
||||
<!-- <script type="module" src="./external-diagrams-mindmap.mjs" /> -->
|
||||
<script type="module">
|
||||
import mindmap from '../../packages/mermaid-mindmap/src/detector';
|
||||
import exampleDiagram from '../../packages/mermaid-example-diagram/src/detector';
|
||||
// import example from '../../packages/mermaid-example-diagram/src/detector';
|
||||
import mermaid from '../../packages/mermaid/src/mermaid';
|
||||
|
||||
await mermaid.registerExternalDiagrams([mindmap]);
|
||||
await mermaid.registerExternalDiagrams([exampleDiagram]);
|
||||
await mermaid.initialize({ logLevel: 0 });
|
||||
await mermaid.initThrowsErrorsAsync();
|
||||
if (window.Cypress) {
|
||||
window.rendered = true;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -21,6 +21,9 @@
|
||||
const diagram = document.getElementById('diagram');
|
||||
const svg = mermaid.render('diagram-svg', graph);
|
||||
diagram.innerHTML = svg;
|
||||
if (window.Cypress) {
|
||||
window.rendered = true;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -21,6 +21,9 @@
|
||||
const diagram = document.getElementById('diagram');
|
||||
const svg = mermaid.render('diagram-svg', graph);
|
||||
diagram.innerHTML = svg;
|
||||
if (window.Cypress) {
|
||||
window.rendered = true;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -94,6 +94,9 @@
|
||||
// document.querySelector('#diagram').innerHTML = diagram;
|
||||
mermaid.render('diagram', diagram, (res) => {
|
||||
document.querySelector('#res').innerHTML = res;
|
||||
if (window.Cypress) {
|
||||
window.rendered = true;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
@ -54,39 +54,205 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div>Security check</div>
|
||||
<pre id="diagram" class="mermaid">
|
||||
flowchart LR
|
||||
%% Actors
|
||||
A
|
||||
subgraph Sub
|
||||
B --> C
|
||||
end
|
||||
|
||||
%% Accusations
|
||||
A --L --> Sub
|
||||
|
||||
%% Offense
|
||||
B --> A
|
||||
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
stateDiagram-v2
|
||||
|
||||
[*] --> S1
|
||||
S1 --> S2: long line using<br/>should work
|
||||
S1 --> S3: long line using <br>should work
|
||||
S1 --> S4: long line using \\nshould work
|
||||
|
||||
%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%
|
||||
graph BT
|
||||
a{The cat in the hat} -- 1o --> b
|
||||
a -- 2o --> c
|
||||
a -- 3o --> d
|
||||
g --2i--> a
|
||||
d --1i--> a
|
||||
h --3i -->a
|
||||
b --> d(The dog in the hog)
|
||||
c --> d
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
gantt
|
||||
title Style today marker (vertical line should be 5px wide and half-transparent blue)
|
||||
dateFormat YYYY-MM-DD
|
||||
axisFormat %d
|
||||
todayMarker stroke-width:5px,stroke:#00f,opacity:0.5
|
||||
section Section1
|
||||
Today: 1, -1h
|
||||
flowchart-elk TB
|
||||
a --> b
|
||||
a --> c
|
||||
b --> d
|
||||
c --> d
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%
|
||||
flowchart TB
|
||||
%% I could not figure out how to use double quotes in labels in Mermaid
|
||||
subgraph ibm[IBM Espresso CPU]
|
||||
core0[IBM PowerPC Broadway Core 0]
|
||||
core1[IBM PowerPC Broadway Core 1]
|
||||
core2[IBM PowerPC Broadway Core 2]
|
||||
|
||||
rom[16 KB ROM]
|
||||
|
||||
core0 --- core2
|
||||
|
||||
rom --> core2
|
||||
end
|
||||
|
||||
subgraph amd[AMD Latte GPU]
|
||||
mem[Memory & I/O Bridge]
|
||||
dram[DRAM Controller]
|
||||
edram[32 MB EDRAM MEM1]
|
||||
rom[512 B SEEPROM]
|
||||
|
||||
sata[SATA IF]
|
||||
exi[EXI]
|
||||
|
||||
subgraph gx[GX]
|
||||
sram[3 MB 1T-SRAM]
|
||||
end
|
||||
|
||||
radeon[AMD Radeon R7xx GX2]
|
||||
|
||||
mem --- gx
|
||||
mem --- radeon
|
||||
|
||||
rom --- mem
|
||||
|
||||
mem --- sata
|
||||
mem --- exi
|
||||
|
||||
dram --- sata
|
||||
dram --- exi
|
||||
end
|
||||
|
||||
ddr3[2 GB DDR3 RAM MEM2]
|
||||
|
||||
mem --- ddr3
|
||||
dram --- ddr3
|
||||
edram --- ddr3
|
||||
|
||||
core1 --- mem
|
||||
|
||||
exi --- rtc
|
||||
rtc{{rtc}}
|
||||
</pre
|
||||
>
|
||||
<br />
|
||||
<pre id="diagram" class="mermaid2">
|
||||
flowchart TB
|
||||
%% I could not figure out how to use double quotes in labels in Mermaid
|
||||
subgraph ibm[IBM Espresso CPU]
|
||||
core0[IBM PowerPC Broadway Core 0]
|
||||
core1[IBM PowerPC Broadway Core 1]
|
||||
core2[IBM PowerPC Broadway Core 2]
|
||||
|
||||
rom[16 KB ROM]
|
||||
|
||||
core0 --- core2
|
||||
|
||||
rom --> core2
|
||||
end
|
||||
|
||||
subgraph amd[AMD Latte GPU]
|
||||
mem[Memory & I/O Bridge]
|
||||
dram[DRAM Controller]
|
||||
edram[32 MB EDRAM MEM1]
|
||||
rom[512 B SEEPROM]
|
||||
|
||||
sata[SATA IF]
|
||||
exi[EXI]
|
||||
|
||||
subgraph gx[GX]
|
||||
sram[3 MB 1T-SRAM]
|
||||
end
|
||||
|
||||
radeon[AMD Radeon R7xx GX2]
|
||||
|
||||
mem --- gx
|
||||
mem --- radeon
|
||||
|
||||
rom --- mem
|
||||
|
||||
mem --- sata
|
||||
mem --- exi
|
||||
|
||||
dram --- sata
|
||||
dram --- exi
|
||||
end
|
||||
|
||||
ddr3[2 GB DDR3 RAM MEM2]
|
||||
|
||||
mem --- ddr3
|
||||
dram --- ddr3
|
||||
edram --- ddr3
|
||||
|
||||
core1 --- mem
|
||||
|
||||
exi --- rtc
|
||||
rtc{{rtc}}
|
||||
</pre
|
||||
>
|
||||
<br />
|
||||
|
||||
<pre id="diagram" class="mermaid2">
|
||||
flowchart LR
|
||||
B1 --be be--x B2
|
||||
B1 --bo bo--o B3
|
||||
subgraph Ugge
|
||||
B2
|
||||
B3
|
||||
subgraph inner
|
||||
B4
|
||||
B5
|
||||
end
|
||||
subgraph inner2
|
||||
subgraph deeper
|
||||
C4
|
||||
C5
|
||||
end
|
||||
C6
|
||||
end
|
||||
|
||||
B4 --> C4
|
||||
|
||||
B3 -- X --> B4
|
||||
B2 --> inner
|
||||
|
||||
C4 --> C5
|
||||
end
|
||||
|
||||
subgraph outer
|
||||
B6
|
||||
end
|
||||
B6 --> B5
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
sequenceDiagram
|
||||
Customer->>+Stripe: Makes a payment request
|
||||
Stripe->>+Bank: Forwards the payment request to the bank
|
||||
Bank->>+Customer: Asks for authorization
|
||||
Customer->>+Bank: Provides authorization
|
||||
Bank->>+Stripe: Sends a response with payment details
|
||||
Stripe->>+Merchant: Sends a notification of payment receipt
|
||||
Merchant->>+Stripe: Confirms the payment
|
||||
Stripe->>+Customer: Sends a confirmation of payment
|
||||
Customer->>+Merchant: Receives goods or services
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
mindmap
|
||||
root((mindmap))
|
||||
Origins
|
||||
Long history
|
||||
::icon(fa fa-book)
|
||||
Popularisation
|
||||
British popular psychology author Tony Buzan
|
||||
Research
|
||||
On effectiveness<br/>and features
|
||||
On Automatic creation
|
||||
Uses
|
||||
Creative techniques
|
||||
Strategic planning
|
||||
Argument mapping
|
||||
Tools
|
||||
Pen and paper
|
||||
Mermaid
|
||||
</pre>
|
||||
<br />
|
||||
<pre id="diagram" class="mermaid2">
|
||||
example-diagram
|
||||
</pre>
|
||||
|
||||
<!-- <div id="cy"></div> -->
|
||||
@ -96,18 +262,19 @@ flowchart LR
|
||||
<!-- <script src="./mermaid.js"></script> -->
|
||||
|
||||
<script type="module">
|
||||
import mindmap from '../../packages/mermaid-mindmap/src/detector';
|
||||
// import example from '../../packages/mermaid-example-diagram/src/detector';
|
||||
// import mindmap from '../../packages/mermaid-mindmap/src/detector';
|
||||
import example from '../../packages/mermaid-example-diagram/src/detector';
|
||||
import mermaid from '../../packages/mermaid/src/mermaid';
|
||||
await mermaid.registerExternalDiagrams([mindmap]);
|
||||
await mermaid.registerExternalDiagrams([example]);
|
||||
mermaid.parseError = function (err, hash) {
|
||||
// console.error('Mermaid error: ', err);
|
||||
};
|
||||
mermaid.initialize({
|
||||
theme: 'default',
|
||||
theme: 'forest',
|
||||
startOnLoad: true,
|
||||
logLevel: 0,
|
||||
logLevel: 5,
|
||||
flowchart: {
|
||||
// defaultRenderer: 'elk',
|
||||
useMaxWidth: false,
|
||||
htmlLabels: true,
|
||||
},
|
||||
|
@ -1,81 +1,93 @@
|
||||
<html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Mindmap Mermaid Quick Test Page</title>
|
||||
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=" />
|
||||
<style>
|
||||
body {
|
||||
/* background: rgb(221, 208, 208); */
|
||||
/* background:#333; */
|
||||
font-family: 'Arial';
|
||||
/* font-size: 18px !important; */
|
||||
}
|
||||
h1 {
|
||||
color: grey;
|
||||
}
|
||||
.mermaid2 {
|
||||
display: none;
|
||||
}
|
||||
.mermaid svg {
|
||||
/* font-size: 18px !important; */
|
||||
background-color: #eee;
|
||||
background-image: radial-gradient(#fff 1%, transparent 11%),
|
||||
radial-gradient(#fff 1%, transparent 11%);
|
||||
background-size: 20px 20px;
|
||||
background-position: 0 0, 10px 10px;
|
||||
background-repeat: repeat;
|
||||
}
|
||||
.malware {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 150px;
|
||||
background: red;
|
||||
color: black;
|
||||
display: flex;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: monospace;
|
||||
font-size: 72px;
|
||||
div.mermaid {
|
||||
/* font-family: 'trebuchet ms', verdana, arial; */
|
||||
font-family: 'Courier New', Courier, monospace !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>Security check</div>
|
||||
<pre id="diagram" class="mermaid">
|
||||
graph TD
|
||||
A["test"] --"<p><style> * { display : none}</style>test</p>"--> B
|
||||
<h1>Mindmap diagram demo</h1>
|
||||
<pre class="mermaid">
|
||||
mindmap
|
||||
root
|
||||
child1((Circle))
|
||||
grandchild 1
|
||||
grandchild 2
|
||||
child2(Round rectangle)
|
||||
grandchild 3
|
||||
grandchild 4
|
||||
child3[Square]
|
||||
grandchild 5
|
||||
::icon(mdi mdi-fire)
|
||||
gc6((grand<br/>child 6))
|
||||
::icon(mdi mdi-fire)
|
||||
gc7((grand<br/>grand<br/>child 8))
|
||||
</pre>
|
||||
|
||||
<!-- <div id="cy"></div> -->
|
||||
<!-- <script src="http://localhost:9000/packages/mermaid-mindmap/dist/mermaid-mindmap-detector.js"></script> -->
|
||||
<!-- <script src="./mermaid-example-diagram-detector.js"></script> -->
|
||||
<!-- <script src="//cdn.jsdelivr.net/npm/mermaid@9.1.7/dist/mermaid.min.js"></script> -->
|
||||
<!-- <script src="./mermaid.js"></script> -->
|
||||
<h2>Mindmap with root wrapping text and a shape</h2>
|
||||
<pre class="mermaid">
|
||||
mindmap
|
||||
root[A root with a long text that wraps to keep the node size in check]
|
||||
</pre>
|
||||
|
||||
<script type="module">
|
||||
import mindmap from '../../packages/mermaid-mindmap/src/detector';
|
||||
// import example from '../../packages/mermaid-example-diagram/src/detector';
|
||||
// import mermaid from './mermaid.esm.mjs';
|
||||
import mermaid from '../../packages/mermaid/src/mermaid';
|
||||
await mermaid.registerExternalDiagrams([mindmap]);
|
||||
// import mermaidMindmap from './mermaid-mindmap.esm.mjs';
|
||||
|
||||
// import mermaidMindmap from 'https://cdn.jsdelivr.net/npm/@mermaid-js/mermaid-mindmap@9.3.0/+esm';
|
||||
// await mermaid.registerExternalDiagrams([mermaidMindmap]);
|
||||
|
||||
const ALLOWED_TAGS = [
|
||||
'a',
|
||||
'b',
|
||||
'blockquote',
|
||||
'br',
|
||||
'dd',
|
||||
'div',
|
||||
'dl',
|
||||
'dt',
|
||||
'em',
|
||||
'foreignObject',
|
||||
'h1',
|
||||
'h2',
|
||||
'h3',
|
||||
'h4',
|
||||
'h5',
|
||||
'h6',
|
||||
'h7',
|
||||
'h8',
|
||||
'hr',
|
||||
'i',
|
||||
'li',
|
||||
'ul',
|
||||
'ol',
|
||||
'p',
|
||||
'pre',
|
||||
'span',
|
||||
'strike',
|
||||
'strong',
|
||||
'table',
|
||||
'tbody',
|
||||
'td',
|
||||
'tfoot',
|
||||
'th',
|
||||
'thead',
|
||||
'tr',
|
||||
];
|
||||
mermaid.parseError = function (err, hash) {
|
||||
// console.error('Mermaid error: ', err);
|
||||
};
|
||||
mermaid.initialize({
|
||||
theme: 'default',
|
||||
theme: 'base',
|
||||
startOnLoad: true,
|
||||
logLevel: 0,
|
||||
flowchart: {
|
||||
@ -94,10 +106,6 @@
|
||||
console.error('In parse error:');
|
||||
console.error(err);
|
||||
};
|
||||
// mermaid.test1('first_slow', 1200).then((r) => console.info(r));
|
||||
// mermaid.test1('second_fast', 200).then((r) => console.info(r));
|
||||
// mermaid.test1('third_fast', 200).then((r) => console.info(r));
|
||||
// mermaid.test1('forth_slow', 1200).then((r) => console.info(r));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,14 +1,283 @@
|
||||
<html>
|
||||
<head>
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<style>
|
||||
body {
|
||||
/* background: rgb(221, 208, 208); */
|
||||
/* background:#333; */
|
||||
font-family: 'Arial';
|
||||
/* font-size: 18px !important; */
|
||||
}
|
||||
h1 {
|
||||
color: grey;
|
||||
}
|
||||
.mermaid2 {
|
||||
display: none;
|
||||
}
|
||||
.mermaid svg {
|
||||
/* font-size: 18px !important; */
|
||||
background-color: #eee;
|
||||
background-image: radial-gradient(#fff 1%, transparent 11%),
|
||||
radial-gradient(#fff 1%, transparent 11%);
|
||||
background-size: 20px 20px;
|
||||
background-position: 0 0, 10px 10px;
|
||||
background-repeat: repeat;
|
||||
}
|
||||
.malware {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 150px;
|
||||
background: red;
|
||||
color: black;
|
||||
display: flex;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: monospace;
|
||||
font-size: 72px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<pre class="mermaid">
|
||||
none
|
||||
hello world
|
||||
<pre id="diagram" class="mermaid">
|
||||
%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%
|
||||
graph TB
|
||||
a --> b
|
||||
a --> c
|
||||
b --> d
|
||||
c --> d
|
||||
</pre>
|
||||
<script src="./mermaid.js"></script>
|
||||
<script>
|
||||
<pre id="diagram" class="mermaid">
|
||||
flowchart-elk LR
|
||||
subgraph A
|
||||
a -->b
|
||||
end
|
||||
subgraph B
|
||||
b
|
||||
end
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%
|
||||
flowchart TB
|
||||
%% I could not figure out how to use double quotes in labels in Mermaid
|
||||
subgraph ibm[IBM Espresso CPU]
|
||||
core0[IBM PowerPC Broadway Core 0]
|
||||
core1[IBM PowerPC Broadway Core 1]
|
||||
core2[IBM PowerPC Broadway Core 2]
|
||||
|
||||
rom[16 KB ROM]
|
||||
|
||||
core0 --- core2
|
||||
|
||||
rom --> core2
|
||||
end
|
||||
|
||||
subgraph amd[AMD Latte GPU]
|
||||
mem[Memory & I/O Bridge]
|
||||
dram[DRAM Controller]
|
||||
edram[32 MB EDRAM MEM1]
|
||||
rom[512 B SEEPROM]
|
||||
|
||||
sata[SATA IF]
|
||||
exi[EXI]
|
||||
|
||||
subgraph gx[GX]
|
||||
sram[3 MB 1T-SRAM]
|
||||
end
|
||||
|
||||
radeon[AMD Radeon R7xx GX2]
|
||||
|
||||
mem --- gx
|
||||
mem --- radeon
|
||||
|
||||
rom --- mem
|
||||
|
||||
mem --- sata
|
||||
mem --- exi
|
||||
|
||||
dram --- sata
|
||||
dram --- exi
|
||||
end
|
||||
|
||||
ddr3[2 GB DDR3 RAM MEM2]
|
||||
|
||||
mem --- ddr3
|
||||
dram --- ddr3
|
||||
edram --- ddr3
|
||||
|
||||
core1 --- mem
|
||||
|
||||
exi --- rtc
|
||||
rtc{{rtc}}
|
||||
</pre
|
||||
>
|
||||
<br />
|
||||
<pre id="diagram" class="mermaid">
|
||||
flowchart TB
|
||||
%% I could not figure out how to use double quotes in labels in Mermaid
|
||||
subgraph ibm[IBM Espresso CPU]
|
||||
core0[IBM PowerPC Broadway Core 0]
|
||||
core1[IBM PowerPC Broadway Core 1]
|
||||
core2[IBM PowerPC Broadway Core 2]
|
||||
|
||||
rom[16 KB ROM]
|
||||
|
||||
core0 --- core2
|
||||
|
||||
rom --> core2
|
||||
end
|
||||
|
||||
subgraph amd[AMD Latte GPU]
|
||||
mem[Memory & I/O Bridge]
|
||||
dram[DRAM Controller]
|
||||
edram[32 MB EDRAM MEM1]
|
||||
rom[512 B SEEPROM]
|
||||
|
||||
sata[SATA IF]
|
||||
exi[EXI]
|
||||
|
||||
subgraph gx[GX]
|
||||
sram[3 MB 1T-SRAM]
|
||||
end
|
||||
|
||||
radeon[AMD Radeon R7xx GX2]
|
||||
|
||||
mem --- gx
|
||||
mem --- radeon
|
||||
|
||||
rom --- mem
|
||||
|
||||
mem --- sata
|
||||
mem --- exi
|
||||
|
||||
dram --- sata
|
||||
dram --- exi
|
||||
end
|
||||
|
||||
ddr3[2 GB DDR3 RAM MEM2]
|
||||
|
||||
mem --- ddr3
|
||||
dram --- ddr3
|
||||
edram --- ddr3
|
||||
|
||||
core1 --- mem
|
||||
|
||||
exi --- rtc
|
||||
rtc{{rtc}}
|
||||
</pre
|
||||
>
|
||||
<br />
|
||||
|
||||
<pre id="diagram" class="mermaid2">
|
||||
flowchart LR
|
||||
B1 --be be--x B2
|
||||
B1 --bo bo--o B3
|
||||
subgraph Ugge
|
||||
B2
|
||||
B3
|
||||
subgraph inner
|
||||
B4
|
||||
B5
|
||||
end
|
||||
subgraph inner2
|
||||
subgraph deeper
|
||||
C4
|
||||
C5
|
||||
end
|
||||
C6
|
||||
end
|
||||
|
||||
B4 --> C4
|
||||
|
||||
B3 -- X --> B4
|
||||
B2 --> inner
|
||||
|
||||
C4 --> C5
|
||||
end
|
||||
|
||||
subgraph outer
|
||||
B6
|
||||
end
|
||||
B6 --> B5
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
sequenceDiagram
|
||||
Customer->>+Stripe: Makes a payment request
|
||||
Stripe->>+Bank: Forwards the payment request to the bank
|
||||
Bank->>+Customer: Asks for authorization
|
||||
Customer->>+Bank: Provides authorization
|
||||
Bank->>+Stripe: Sends a response with payment details
|
||||
Stripe->>+Merchant: Sends a notification of payment receipt
|
||||
Merchant->>+Stripe: Confirms the payment
|
||||
Stripe->>+Customer: Sends a confirmation of payment
|
||||
Customer->>+Merchant: Receives goods or services
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
gantt
|
||||
title Style today marker (vertical line should be 5px wide and half-transparent blue)
|
||||
dateFormat YYYY-MM-DD
|
||||
axisFormat %d
|
||||
todayMarker stroke-width:5px,stroke:#00f,opacity:0.5
|
||||
section Section1
|
||||
Today: 1, -1h
|
||||
</pre>
|
||||
|
||||
<!-- <div id="cy"></div> -->
|
||||
<!-- <script src="http://localhost:9000/packages/mermaid-mindmap/dist/mermaid-mindmap-detector.js"></script> -->
|
||||
<!-- <script src="./mermaid-example-diagram-detector.js"></script> -->
|
||||
<!-- <script src="//cdn.jsdelivr.net/npm/mermaid@9.1.7/dist/mermaid.min.js"></script> -->
|
||||
<!-- <script src="./mermaid.js"></script> -->
|
||||
|
||||
<script type="module">
|
||||
import mindmap from '../../packages/mermaid-mindmap/src/detector';
|
||||
// import example from '../../packages/mermaid-example-diagram/src/detector';
|
||||
import mermaid from '../../packages/mermaid/src/mermaid';
|
||||
await mermaid.registerExternalDiagrams([mindmap]);
|
||||
mermaid.parseError = function (err, hash) {
|
||||
// console.error('Mermaid error: ', err);
|
||||
};
|
||||
mermaid.initialize({
|
||||
logLevel: 1,
|
||||
// theme: 'forest',
|
||||
startOnLoad: true,
|
||||
logLevel: 0,
|
||||
flowchart: {
|
||||
// defaultRenderer: 'elk',
|
||||
useMaxWidth: false,
|
||||
htmlLabels: true,
|
||||
},
|
||||
gantt: {
|
||||
useMaxWidth: false,
|
||||
},
|
||||
useMaxWidth: false,
|
||||
});
|
||||
function callback() {
|
||||
alert('It worked');
|
||||
}
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('In parse error:');
|
||||
console.error(err);
|
||||
};
|
||||
// mermaid.test1('first_slow', 1200).then((r) => console.info(r));
|
||||
// mermaid.test1('second_fast', 200).then((r) => console.info(r));
|
||||
// mermaid.test1('third_fast', 200).then((r) => console.info(r));
|
||||
// mermaid.test1('forth_slow', 1200).then((r) => console.info(r));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,10 +1,17 @@
|
||||
import mermaid2 from '../../packages/mermaid/src/mermaid';
|
||||
import mindmap from '../../packages/mermaid-mindmap/src/detector';
|
||||
import externalExample from '../../packages/mermaid-example-diagram/src/detector';
|
||||
|
||||
function b64ToUtf8(str) {
|
||||
return decodeURIComponent(escape(window.atob(str)));
|
||||
}
|
||||
|
||||
// Adds a rendered flag to window when rendering is done, so cypress can wait for it.
|
||||
function markRendered() {
|
||||
if (window.Cypress) {
|
||||
window.rendered = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ##contentLoaded Callback function that is called when page is loaded. This functions fetches
|
||||
* configuration for mermaid rendering and calls init for rendering the mermaid diagrams on the
|
||||
@ -37,9 +44,10 @@ const contentLoaded = async function () {
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
}
|
||||
|
||||
await mermaid2.registerExternalDiagrams([mindmap]);
|
||||
await mermaid2.registerExternalDiagrams([externalExample]);
|
||||
mermaid2.initialize(graphObj.mermaid);
|
||||
mermaid2.init();
|
||||
await mermaid2.init();
|
||||
markRendered();
|
||||
}
|
||||
};
|
||||
|
||||
@ -128,6 +136,7 @@ const contentLoadedApi = function () {
|
||||
);
|
||||
}
|
||||
}
|
||||
markRendered();
|
||||
};
|
||||
|
||||
if (typeof document !== 'undefined') {
|
||||
@ -142,7 +151,7 @@ if (typeof document !== 'undefined') {
|
||||
contentLoadedApi();
|
||||
} else {
|
||||
this.console.log('Not using api');
|
||||
contentLoaded();
|
||||
void contentLoaded();
|
||||
}
|
||||
},
|
||||
false
|
||||
|
@ -17,10 +17,10 @@
|
||||
<h1>Class diagram demos</h1>
|
||||
|
||||
<pre class="mermaid">
|
||||
---
|
||||
title: Demo Class Diagram
|
||||
---
|
||||
classDiagram
|
||||
---
|
||||
title: Demo Class Diagram
|
||||
---
|
||||
classDiagram
|
||||
accTitle: Demo Class Diagram
|
||||
accDescr: This class diagram show the abstract Animal class, and 3 classes that inherit from it: Duck, Fish, and Zebra.
|
||||
|
||||
@ -138,7 +138,20 @@ title: Demo Class Diagram
|
||||
Pineapple : -int leafCount()
|
||||
Pineapple : -int spikeCount()
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class Person {
|
||||
+Id : Guid
|
||||
+FirstName : string
|
||||
+LastName : string
|
||||
-privateProperty : string
|
||||
#ProtectedProperty : string
|
||||
~InternalProperty : string
|
||||
~AnotherInternalProperty : List~List~string~~
|
||||
}
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<script src="./mermaid.js"></script>
|
||||
|
109
demos/er.html
109
demos/er.html
@ -19,43 +19,94 @@
|
||||
|
||||
<body>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
title: This is a title
|
||||
---
|
||||
erDiagram
|
||||
%% title This is a title
|
||||
%% accDescription Test a description
|
||||
|
||||
---
|
||||
title: This is a title
|
||||
---
|
||||
erDiagram
|
||||
%% title This is a title
|
||||
%% accDescription Test a description
|
||||
"Person . CUSTOMER"||--o{ ORDER : places
|
||||
|
||||
"Person . CUSTOMER"||--o{ ORDER : places
|
||||
ORDER ||--|{ "€£LINE_ITEM ¥" : contains
|
||||
|
||||
ORDER ||--|{ "€£LINE_ITEM ¥" : contains
|
||||
"Person . CUSTOMER" }|..|{ "Address//StreetAddress::[DELIVERY ADDRESS]" : uses
|
||||
|
||||
"Person . CUSTOMER" }|..|{ "Address//StreetAddress::[DELIVERY ADDRESS]" : uses
|
||||
"Address//StreetAddress::[DELIVERY ADDRESS]" {
|
||||
int customerID FK
|
||||
string line1 "this is the first address line comment"
|
||||
string line2
|
||||
string city
|
||||
string region
|
||||
string state
|
||||
string(5) postal_code
|
||||
string country
|
||||
}
|
||||
|
||||
"Address//StreetAddress::[DELIVERY ADDRESS]" {
|
||||
int customerID FK
|
||||
string line1 "this is the first address line comment"
|
||||
string line2
|
||||
string city
|
||||
string region
|
||||
string state
|
||||
string postal_code
|
||||
string country
|
||||
"a_~`!@#$^&*()-_=+[]{}|/;:'.?¡⁄™€£‹¢›∞fi§‡•°ª·º‚≠±œŒ∑„®†ˇ¥Á¨ˆˆØπ∏“«»åÅßÍ∂΃ϩ˙Ó∆Ô˚¬Ò…ÚæÆΩ¸≈π˛çÇ√◊∫ı˜µÂ≤¯≥˘÷¿" {
|
||||
string name "this is an entity with an absurd name just to show characters that are now acceptable as long as the name is in double quotes"
|
||||
}
|
||||
|
||||
"€£LINE_ITEM ¥" {
|
||||
int orderID FK
|
||||
int currencyId FK
|
||||
number price
|
||||
number quantity
|
||||
number adjustment
|
||||
number final_price
|
||||
}
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<pre class="mermaid">
|
||||
erDiagram
|
||||
"HOSPITAL" {
|
||||
int id PK
|
||||
int doctor_id FK
|
||||
string address UK
|
||||
string name
|
||||
string phone_number
|
||||
string fax_number
|
||||
}
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
"a_~`!@#$^&*()-_=+[]{}|/;:'.?¡⁄™€£‹¢›∞fi§‡•°ª·º‚≠±œŒ∑„®†ˇ¥Á¨ˆˆØπ∏“«»åÅßÍ∂΃ϩ˙Ó∆Ô˚¬Ò…ÚæÆΩ¸≈π˛çÇ√◊∫ı˜µÂ≤¯≥˘÷¿" {
|
||||
string name "this is an entity with an absurd name just to show characters that are now acceptable as long as the name is in double quotes"
|
||||
}
|
||||
<pre class="mermaid">
|
||||
erDiagram
|
||||
"HOSPITAL" {
|
||||
int id PK
|
||||
int doctor_id PK, FK
|
||||
string address UK
|
||||
string name
|
||||
string phone_number
|
||||
string fax_number
|
||||
}
|
||||
</pre
|
||||
>
|
||||
<hr />
|
||||
|
||||
"€£LINE_ITEM ¥" {
|
||||
int orderID FK
|
||||
int currencyId FK
|
||||
number price
|
||||
number quantity
|
||||
number adjustment
|
||||
number final_price
|
||||
}
|
||||
<pre class="mermaid">
|
||||
erDiagram
|
||||
CAR ||--o{ NAMED-DRIVER : allows
|
||||
CAR {
|
||||
string registrationNumber PK
|
||||
string make
|
||||
string model
|
||||
string[] parts
|
||||
}
|
||||
PERSON ||--o{ NAMED-DRIVER : is
|
||||
PERSON {
|
||||
string driversLicense PK "The license #"
|
||||
string(99) firstName "Only 99 characters are allowed"
|
||||
string lastName
|
||||
string phone UK
|
||||
int age
|
||||
}
|
||||
NAMED-DRIVER {
|
||||
string carRegistrationNumber PK, FK
|
||||
string driverLicence PK,FK
|
||||
}
|
||||
MANUFACTURER only one to zero or more CAR : makes
|
||||
</pre>
|
||||
|
||||
<script src="./mermaid.js"></script>
|
||||
|
@ -17,9 +17,9 @@
|
||||
<h2>Sample 1</h2>
|
||||
<h3>graph</h3>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
title: This is a complicated flow
|
||||
---
|
||||
---
|
||||
title: This is a complicated flow
|
||||
---
|
||||
graph LR
|
||||
accTitle: This is a complicated flow
|
||||
accDescr: This is the descriptoin for the complicated flow.
|
||||
@ -224,9 +224,9 @@ title: This is a complicated flow
|
||||
<h2>Sample 2</h2>
|
||||
<h3>graph</h3>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
title: What to buy
|
||||
---
|
||||
---
|
||||
title: What to buy
|
||||
---
|
||||
graph TD
|
||||
accTitle: What to buy
|
||||
accDescr: Options of what to buy with Christmas money
|
||||
|
@ -16,9 +16,9 @@
|
||||
<body>
|
||||
<h1>Git diagram demo</h1>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
title: Simple Git diagram
|
||||
---
|
||||
---
|
||||
title: Simple Git diagram
|
||||
---
|
||||
gitGraph:
|
||||
options
|
||||
{
|
||||
|
@ -16,9 +16,9 @@
|
||||
<body>
|
||||
<h1>Journey diagram demo</h1>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
title: My working day
|
||||
---
|
||||
---
|
||||
title: My working day
|
||||
---
|
||||
journey
|
||||
accTitle: Very simple journey demo
|
||||
accDescr: 2 main sections: work and home, each with just a few tasks
|
||||
|
@ -128,6 +128,22 @@
|
||||
</pre>
|
||||
<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
|
||||
>
|
||||
<hr />
|
||||
|
||||
<script src="./mermaid.js"></script>
|
||||
<script>
|
||||
mermaid.initialize({
|
||||
|
@ -17,11 +17,11 @@
|
||||
<h1>State diagram demos</h1>
|
||||
<h2>Very simple showing change from State1 to State2</h2>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
title: Very simple diagram
|
||||
---
|
||||
stateDiagram
|
||||
accTitle: This is the accessible title
|
||||
---
|
||||
title: Very simple diagram
|
||||
---
|
||||
stateDiagram
|
||||
accTitle: This is the accessible title
|
||||
accDescr:This is an accessible description
|
||||
State1 --> State2
|
||||
</pre>
|
||||
@ -47,13 +47,13 @@ title: Very simple diagram
|
||||
</code>
|
||||
</p>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
title: Very simple diagram
|
||||
---
|
||||
stateDiagram
|
||||
---
|
||||
title: Very simple diagram
|
||||
---
|
||||
stateDiagram
|
||||
direction TB
|
||||
|
||||
accTitle: This is the accessible title
|
||||
accTitle: This is the accessible title
|
||||
accDescr: This is an accessible description
|
||||
|
||||
classDef notMoving fill:white
|
||||
@ -161,12 +161,19 @@ title: Very simple diagram
|
||||
First --> Second
|
||||
First --> Third
|
||||
|
||||
state First {
|
||||
state "the first composite" as First {
|
||||
[*] --> 1st
|
||||
1st --> [*]
|
||||
state innerFirst {
|
||||
state "1 in innerFirst" as 1st1st
|
||||
1st2nd: 2 in innerFirst
|
||||
[*] --> 1st1st
|
||||
1st1st --> 1st2nd
|
||||
%% 1st2nd --> 1st
|
||||
}
|
||||
1st --> innerFirst
|
||||
innerFirst --> 2nd
|
||||
}
|
||||
state Second {
|
||||
[*] --> 2nd
|
||||
2nd --> [*]
|
||||
}
|
||||
state Third {
|
||||
|
38
demos/timeline.html
Normal file
38
demos/timeline.html
Normal file
@ -0,0 +1,38 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Mermaid Quick Test Page</title>
|
||||
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=" />
|
||||
<style>
|
||||
div.mermaid {
|
||||
/* font-family: 'trebuchet ms', verdana, arial; */
|
||||
font-family: 'Courier New', Courier, monospace !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<pre class="mermaid">
|
||||
timeline
|
||||
title My day
|
||||
section Go to work
|
||||
1930 : first step : second step
|
||||
: third step
|
||||
1940 : fourth step : fifth step
|
||||
</pre>
|
||||
|
||||
<script src="./mermaid.js"></script>
|
||||
<script>
|
||||
mermaid.initialize({
|
||||
theme: 'forest',
|
||||
logLevel: 1,
|
||||
securityLevel: 'loose',
|
||||
flowchart: { curve: 'basis' },
|
||||
gantt: { axisFormat: '%m/%d/%Y' },
|
||||
sequence: { actorMargin: 50 },
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -497,7 +497,7 @@ mermaidAPI.initialize({
|
||||
- Clarify the need for a CSS stylesheet [#413](https://github.com/knsv/mermaid/pull/413) ([sifb](https://github.com/sifb))
|
||||
- Added hads downstream project [#412](https://github.com/knsv/mermaid/pull/412) ([sinedied](https://github.com/sinedied))
|
||||
- update usage and fix #273 [#406](https://github.com/knsv/mermaid/pull/406) ([jinntrance](https://github.com/jinntrance))
|
||||
- Add https://github.com/raghur/mermaid-filter to downstream projects docs page [#404](https://github.com/knsv/mermaid/pull/404) ([raghur](https://github.com/raghur))
|
||||
- Add <https://github.com/raghur/mermaid-filter> to downstream projects docs page [#404](https://github.com/knsv/mermaid/pull/404) ([raghur](https://github.com/raghur))
|
||||
- New neutral theme [#395](https://github.com/knsv/mermaid/pull/395) ([sinedied](https://github.com/sinedied))
|
||||
- fix cli issues [#390](https://github.com/knsv/mermaid/pull/390) ([ben-page](https://github.com/ben-page))
|
||||
- Add missing space for 'Labels out of bounds' section [#386](https://github.com/knsv/mermaid/pull/386) ([The-Alchemist](https://github.com/The-Alchemist))
|
||||
@ -661,7 +661,7 @@ mermaidAPI.initialize({
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Installing “atom-mermaid@0.1.3” failed [#218](https://github.com/knsv/mermaid/issues/218)
|
||||
- Installing “atom-mermaid\@0.1.3” failed [#218](https://github.com/knsv/mermaid/issues/218)
|
||||
- node feature request [#211](https://github.com/knsv/mermaid/issues/211)
|
||||
- Please add prefix for styles [#208](https://github.com/knsv/mermaid/issues/208)
|
||||
- Bad handling of block arguments [#207](https://github.com/knsv/mermaid/issues/207)
|
||||
@ -671,7 +671,7 @@ mermaidAPI.initialize({
|
||||
- Broken CLI Graphs? (v0.5.1) [#196](https://github.com/knsv/mermaid/issues/196)
|
||||
- Static site does not render under HTTPS [#194](https://github.com/knsv/mermaid/issues/194)
|
||||
- Error on simple graph [#192](https://github.com/knsv/mermaid/issues/192)
|
||||
- Escape "~" [#191](https://github.com/knsv/mermaid/issues/191)
|
||||
- Escape "\~" [#191](https://github.com/knsv/mermaid/issues/191)
|
||||
- Trying to add link using 'click' to flowchart [#188](https://github.com/knsv/mermaid/issues/188)
|
||||
- cli: no lines and arrowheads rendered / only dotted lines [#187](https://github.com/knsv/mermaid/issues/187)
|
||||
- text of mermaid div displayed on page [#186](https://github.com/knsv/mermaid/issues/186)
|
||||
@ -793,7 +793,7 @@ mermaidAPI.initialize({
|
||||
**Closed issues:**
|
||||
|
||||
- subgraph background is black in rendered flowchart PNG via CLI [#121](https://github.com/knsv/mermaid/issues/121)
|
||||
- Integrate editor at https://github.com/naseer/mermaid-webapp [#110](https://github.com/knsv/mermaid/issues/110)
|
||||
- Integrate editor at <https://github.com/naseer/mermaid-webapp> [#110](https://github.com/knsv/mermaid/issues/110)
|
||||
- Internet Explorer Support [#99](https://github.com/knsv/mermaid/issues/99)
|
||||
|
||||
## [0.3.5](https://github.com/knsv/mermaid/tree/0.3.5) (2015-02-15)
|
||||
|
@ -60,7 +60,7 @@ Place the renderer in the diagram folder.
|
||||
|
||||
### Step 3: Detection of the new diagram type
|
||||
|
||||
The second thing to do is to add the capability to detect the new new diagram to type to the detectType in utils.js. The detection should return a key for the new diagram type.
|
||||
The second thing to do is to add the capability to detect the new diagram to type to the detectType in utils.js. The detection should return a key for the new diagram type.
|
||||
[This key will be used to as the aria roledescription](#aria-roledescription), so it should be a word that clearly describes the diagram type.
|
||||
For example, if your new diagram use a UML deployment diagram, a good key would be "UMLDeploymentDiagram" because assistive technologies such as a screen reader
|
||||
would voice that as "U-M-L Deployment diagram." Another good key would be "deploymentDiagram" because that would be voiced as "Deployment Diagram." A bad key would be "deployment" because that would not sufficiently describe the diagram.
|
||||
|
@ -32,15 +32,15 @@ Examples are provided in [Getting Started](../intro/n00b-gettingStarted.md)
|
||||
|
||||
**CodePen Examples:**
|
||||
|
||||
https://codepen.io/CarlBoneri/pen/BQwZzq
|
||||
<https://codepen.io/CarlBoneri/pen/BQwZzq>
|
||||
|
||||
https://codepen.io/tdkn/pen/vZxQzd
|
||||
<https://codepen.io/tdkn/pen/vZxQzd>
|
||||
|
||||
https://codepen.io/janzeteachesit/pen/OWWZKN
|
||||
<https://codepen.io/janzeteachesit/pen/OWWZKN>
|
||||
|
||||
## Mermaid with Text Area
|
||||
|
||||
https://codepen.io/Ryuno-Ki/pen/LNxwgR
|
||||
<https://codepen.io/Ryuno-Ki/pen/LNxwgR>
|
||||
|
||||
## Mermaid in open source docs
|
||||
|
||||
|
@ -80,9 +80,12 @@ A **multiple line accessible description** _does not have a colon (`:`) after th
|
||||
|
||||
Ex:
|
||||
|
||||
accDescr { The official Bob's Burgers corporate processes that are used
|
||||
for making very, very big decisions.
|
||||
This is actually a very simple flow: see the big decision and then make the big decision.}
|
||||
```markdown
|
||||
accDescr {
|
||||
This is a multiple line accessible description.
|
||||
It does not have a colon and is surrounded by curly brackets.
|
||||
}
|
||||
```
|
||||
|
||||
See [the accTitle and accDescr usage examples](#acctitle-and-accdescr-usage-examples) for how this can be used in a diagram and the resulting HTML generated.
|
||||
|
||||
|
@ -32,7 +32,8 @@ Mermaid basically supports two types of configuration options to be overridden b
|
||||
|
||||
**NOTE:** These options listed here are not all the configuration options. To get hold of all the configuration options, please refer to the [defaultConfig.ts](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/defaultConfig.ts) in the source code.
|
||||
|
||||
Soon we plan to publish a complete list of top-level configurations & all the diagram specific configurations, with their possible values in the docs
|
||||
> **Note**
|
||||
> We plan to publish a complete list of top-level configurations & all the diagram specific configurations, with their possible values in the docs soon.
|
||||
|
||||
## Declaring directives
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
>
|
||||
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
|
||||
>
|
||||
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/misc/faq.md](../../packages/mermaid/src/docs/misc/faq.md).
|
||||
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/config/faq.md](../../packages/mermaid/src/docs/config/faq.md).
|
||||
|
||||
# Frequently Asked Questions
|
||||
|
@ -10,17 +10,21 @@
|
||||
|
||||
A more condensed html code can be achieved by embedding the mermaid code in its own .js file, which is referenced like so:
|
||||
|
||||
stuff stuff
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
```html
|
||||
...
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
The actual mermaid file could for example look like this:
|
||||
|
||||
mermaid content...
|
||||
|
||||
---
|
||||
```javascript
|
||||
mermaid content ...
|
||||
```
|
||||
|
||||
## mermaid configuration options
|
||||
|
||||
...
|
||||
```markdown
|
||||
(coming soon)
|
||||
```
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[defaultConfig.ts:1933](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L1933)
|
||||
[defaultConfig.ts:2084](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L2084)
|
||||
|
||||
---
|
||||
|
||||
|
@ -20,7 +20,7 @@ Renames and re-exports [mermaidAPI](mermaidAPI.md#mermaidapi)
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:72](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L72)
|
||||
[mermaidAPI.ts:74](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L74)
|
||||
|
||||
## Variables
|
||||
|
||||
@ -90,7 +90,7 @@ mermaid.initialize(config);
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:961](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L961)
|
||||
[mermaidAPI.ts:886](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L886)
|
||||
|
||||
## Functions
|
||||
|
||||
@ -121,7 +121,7 @@ Return the last node appended
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:285](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L285)
|
||||
[mermaidAPI.ts:287](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L287)
|
||||
|
||||
---
|
||||
|
||||
@ -147,7 +147,7 @@ the cleaned up svgCode
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:236](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L236)
|
||||
[mermaidAPI.ts:238](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L238)
|
||||
|
||||
---
|
||||
|
||||
@ -159,11 +159,11 @@ Create the user styles
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :---------- | :-------------- | :----------------------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `config` | `MermaidConfig` | configuration that has style and theme settings to use |
|
||||
| `graphType` | `string` | used for checking if classDefs should be applied |
|
||||
| `classDefs` | `undefined` | `null` | `Record`<`string`, `DiagramStyleClassDef`> | the classDefs in the diagram text. Might be null if none were defined. Usually is the result of a call to getClasses(...) |
|
||||
| Name | Type | Description |
|
||||
| :---------- | :------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `config` | `MermaidConfig` | configuration that has style and theme settings to use |
|
||||
| `graphType` | `string` | used for checking if classDefs should be applied |
|
||||
| `classDefs` | `undefined` \| `null` \| `Record`<`string`, `DiagramStyleClassDef`> | the classDefs in the diagram text. Might be null if none were defined. Usually is the result of a call to getClasses(...) |
|
||||
|
||||
#### Returns
|
||||
|
||||
@ -173,7 +173,7 @@ the string with all the user styles
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:165](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L165)
|
||||
[mermaidAPI.ts:167](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L167)
|
||||
|
||||
---
|
||||
|
||||
@ -196,7 +196,7 @@ the string with all the user styles
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:213](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L213)
|
||||
[mermaidAPI.ts:215](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L215)
|
||||
|
||||
---
|
||||
|
||||
@ -223,7 +223,7 @@ with an enclosing block that has each of the cssClasses followed by !important;
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:149](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L149)
|
||||
[mermaidAPI.ts:151](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L151)
|
||||
|
||||
---
|
||||
|
||||
@ -243,7 +243,7 @@ with an enclosing block that has each of the cssClasses followed by !important;
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:129](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L129)
|
||||
[mermaidAPI.ts:131](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L131)
|
||||
|
||||
---
|
||||
|
||||
@ -263,7 +263,7 @@ with an enclosing block that has each of the cssClasses followed by !important;
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:100](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L100)
|
||||
[mermaidAPI.ts:102](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L102)
|
||||
|
||||
---
|
||||
|
||||
@ -289,7 +289,7 @@ Put the svgCode into an iFrame. Return the iFrame code
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:264](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L264)
|
||||
[mermaidAPI.ts:266](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L266)
|
||||
|
||||
---
|
||||
|
||||
@ -314,4 +314,4 @@ Remove any existing elements from the given document
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:335](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L335)
|
||||
[mermaidAPI.ts:337](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L337)
|
||||
|
@ -12,15 +12,15 @@ Themes can now be customized at the site-wide level, or on individual Mermaid di
|
||||
|
||||
## Available Themes
|
||||
|
||||
1. **default** - This is the default theme for all diagrams.
|
||||
1. [**default**](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/themes/theme-default.js) - This is the default theme for all diagrams.
|
||||
|
||||
2. **neutral** - This theme is great for black and white documents that will be printed.
|
||||
2. [**neutral**](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/themes/theme-neutral.js) - This theme is great for black and white documents that will be printed.
|
||||
|
||||
3. **dark** - This theme goes well with dark-colored elements or dark-mode.
|
||||
3. [**dark**](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/themes/theme-dark.js) - This theme goes well with dark-colored elements or dark-mode.
|
||||
|
||||
4. **forest** - This theme contains shades of green.
|
||||
4. [**forest**](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/themes/theme-forest.js) - This theme contains shades of green.
|
||||
|
||||
5. **base** - This is the only theme that can be modified. Use this theme as the base for customizations.
|
||||
5. [**base**](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/themes/theme-base.js) - This is the only theme that can be modified. Use this theme as the base for customizations.
|
||||
|
||||
## Site-wide Theme
|
||||
|
||||
@ -53,6 +53,18 @@ Example of `init` directive setting the `theme` to `forest`:
|
||||
a --> b
|
||||
```
|
||||
|
||||
```mermaid-example
|
||||
%%{init: {'theme':'forest'}}%%
|
||||
graph TD
|
||||
a --> b
|
||||
```
|
||||
|
||||
```mermaid
|
||||
%%{init: {'theme':'forest'}}%%
|
||||
graph TD
|
||||
a --> b
|
||||
```
|
||||
|
||||
> **Reminder**: the only theme that can be customed is the `base` theme. The following section covers how to use `themeVariables` for customizations.
|
||||
|
||||
## Customizing Themes with `themeVariables`
|
||||
@ -127,6 +139,66 @@ Example of modifying `themeVariables` using the `init` directive:
|
||||
end
|
||||
```
|
||||
|
||||
```mermaid-example
|
||||
%%{
|
||||
init: {
|
||||
'theme': 'base',
|
||||
'themeVariables': {
|
||||
'primaryColor': '#BB2528',
|
||||
'primaryTextColor': '#fff',
|
||||
'primaryBorderColor': '#7C0000',
|
||||
'lineColor': '#F8B229',
|
||||
'secondaryColor': '#006100',
|
||||
'tertiaryColor': '#fff'
|
||||
}
|
||||
}
|
||||
}%%
|
||||
graph TD
|
||||
A[Christmas] -->|Get money| B(Go shopping)
|
||||
B --> C{Let me think}
|
||||
B --> G[/Another/]
|
||||
C ==>|One| D[Laptop]
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
subgraph section
|
||||
C
|
||||
D
|
||||
E
|
||||
F
|
||||
G
|
||||
end
|
||||
```
|
||||
|
||||
```mermaid
|
||||
%%{
|
||||
init: {
|
||||
'theme': 'base',
|
||||
'themeVariables': {
|
||||
'primaryColor': '#BB2528',
|
||||
'primaryTextColor': '#fff',
|
||||
'primaryBorderColor': '#7C0000',
|
||||
'lineColor': '#F8B229',
|
||||
'secondaryColor': '#006100',
|
||||
'tertiaryColor': '#fff'
|
||||
}
|
||||
}
|
||||
}%%
|
||||
graph TD
|
||||
A[Christmas] -->|Get money| B(Go shopping)
|
||||
B --> C{Let me think}
|
||||
B --> G[/Another/]
|
||||
C ==>|One| D[Laptop]
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
subgraph section
|
||||
C
|
||||
D
|
||||
E
|
||||
F
|
||||
G
|
||||
end
|
||||
```
|
||||
|
||||
## Color and Color Calculation
|
||||
|
||||
To ensure diagram readability, the default value of certain variables is calculated or derived from other variables. For example, `primaryBorderColor` is derived from the `primaryColor` variable. So if the `primaryColor` variable is customized, Mermaid will adjust `primaryBorderColor` automatically. Adjustments can mean a color inversion, a hue change, a darkening/lightening by 10%, etc.
|
||||
@ -142,13 +214,10 @@ The theming engine will only recognize hex colors and not color names. So, the v
|
||||
| fontFamily | trebuchet ms, verdana, arial | |
|
||||
| fontSize | 16px | Font size in pixels |
|
||||
| primaryColor | #fff4dd | Color to be used as background in nodes, other colors will be derived from this |
|
||||
| primaryBorderColor | calculated from primaryColor | Color to be used as border in nodes using `primaryColor` |
|
||||
| primaryBorderColor | calculated from primaryColor | Color to be used as border in nodes using `primaryColor` |
|
||||
| primaryTextColor | calculated from darkMode #ddd/#333 | Color to be used as text color in nodes using `primaryColor` |
|
||||
| secondaryColor | calculated from primaryColor | |
|
||||
| primaryBorderColor | calculated from primaryColor | Color to be used as border in nodes using `primaryColor` |
|
||||
| secondaryBorderColor | calculated from secondaryColor | Color to be used as border in nodes using `secondaryColor` |
|
||||
| primaryBorderColor | calculated from primaryColor | Color to be used as border in nodes using `primaryColor` |
|
||||
| secondaryTextColor | calculated from secondaryColor | Color to be used as text color in nodes using `secondaryColor` |
|
||||
| tertiaryColor | calculated from primaryColor | |
|
||||
| tertiaryBorderColor | calculated from tertiaryColor | Color to be used as border in nodes using `tertiaryColor` |
|
||||
|
@ -22,24 +22,21 @@ For the majority of users, Using the [Live Editor](https://mermaid.live/) would
|
||||
|
||||
We have compiled some Video [Tutorials](./Tutorials.md) on how to use the mermaid Live Editor.
|
||||
|
||||
**Installing and Hosting Mermaid on a Webpage**
|
||||
### Installing and Hosting Mermaid on a Webpage
|
||||
|
||||
**Using the npm package**
|
||||
**Using the npm package:**
|
||||
|
||||
1. You will need to install node v16, which would have npm.
|
||||
1. You will need to install `node v16`, which would have npm.
|
||||
|
||||
2. download yarn using npm.
|
||||
2. Download `yarn` using npm.
|
||||
|
||||
3. enter the following command:
|
||||
yarn add mermaid
|
||||
3. Enter the following command: `yarn add mermaid`.
|
||||
|
||||
4. At this point, you can add mermaid as a dev dependency using this command:
|
||||
yarn add --dev mermaid
|
||||
4. At this point, you can add mermaid as a dev dependency using this command: `yarn add --dev mermaid`.
|
||||
|
||||
5. Alternatively, you can also deploy mermaid using the script tag in an HTML file with mermaid diagram descriptions.
|
||||
as is shown in the example below
|
||||
5. Alternatively, you can also deploy mermaid using the script tag in an HTML file with mermaid diagram descriptions as is shown in the example below.
|
||||
|
||||
**Hosting mermaid on a web page.**
|
||||
**Hosting mermaid on a web page:**
|
||||
|
||||
> Note:This topic explored in greater depth in the [User Guide for Beginners](../intro/n00b-gettingStarted.md)
|
||||
|
||||
@ -152,7 +149,7 @@ $(document).ready(function () {
|
||||
});
|
||||
```
|
||||
|
||||
Not doing so will most likely result in mermaid rendering graphs that have labels out of bounds. The default integration in mermaid uses the window.load event to start rendering.
|
||||
Not doing so will most likely result in mermaid rendering graphs that have labels out of bounds. The default integration in mermaid uses the window\.load event to start rendering.
|
||||
|
||||
If your page has other fonts in its body those might be used instead of the mermaid font. Specifying the font in your styling is a workaround for this.
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
>
|
||||
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
|
||||
>
|
||||
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/misc/integrations.md](../../packages/mermaid/src/docs/misc/integrations.md).
|
||||
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/ecosystem/integrations.md](../../packages/mermaid/src/docs/ecosystem/integrations.md).
|
||||
|
||||
# Integrations
|
||||
|
||||
@ -21,6 +21,7 @@ They also serve as proof of concept, for the variety of things that can be built
|
||||
- [Azure Devops](https://docs.microsoft.com/en-us/azure/devops/project/wiki/wiki-markdown-guidance?view=azure-devops#add-mermaid-diagrams-to-a-wiki-page) (**Native support**)
|
||||
- [Tuleap](https://docs.tuleap.org/user-guide/writing-in-tuleap.html#graphs) (**Native support**)
|
||||
- [Joplin](https://joplinapp.org) (**Native support**)
|
||||
- [Swimm](https://swimm.io) (**Native support**)
|
||||
- [Notion](https://notion.so) (**Native support**)
|
||||
- [Observable](https://observablehq.com/@observablehq/mermaid) (**Native support**)
|
||||
- [Obsidian](https://help.obsidian.md/How+to/Format+your+notes#Diagram) (**Native support**)
|
||||
@ -94,9 +95,10 @@ They also serve as proof of concept, for the variety of things that can be built
|
||||
|
||||
## Editor Plugins
|
||||
|
||||
- [Vs Code](https://code.visualstudio.com/)
|
||||
- [VS Code](https://code.visualstudio.com/)
|
||||
- [Markdown Preview Mermaid Support](https://marketplace.visualstudio.com/items?itemName=bierner.markdown-mermaid)
|
||||
- [Mermaid Preview](https://marketplace.visualstudio.com/items?itemName=vstirbu.vscode-mermaid-preview)
|
||||
- [Markdown Preview Enhanced](https://marketplace.visualstudio.com/items?itemName=shd101wyy.markdown-preview-enhanced)
|
||||
- [Mermaid Markdown Syntax Highlighting](https://marketplace.visualstudio.com/items?itemName=bpruitt-goddard.mermaid-markdown-syntax-highlighting)
|
||||
- [Mermaid Editor](https://marketplace.visualstudio.com/items?itemName=tomoyukim.vscode-mermaid-editor)
|
||||
- [Mermaid Export](https://marketplace.visualstudio.com/items?itemName=Gruntfuggly.mermaid-export)
|
||||
@ -109,10 +111,10 @@ They also serve as proof of concept, for the variety of things that can be built
|
||||
- [md-it-mermaid](https://github.com/iamcco/md-it-mermaid)
|
||||
- [markdown-it-mermaid-fence-new](https://github.com/Revomatico/markdown-it-mermaid-fence-new)
|
||||
- [markdown-it-mermaid-less](https://github.com/searKing/markdown-it-mermaid-less)
|
||||
- [Atom](https://atom.io)
|
||||
- [Markdown Preview Enhanced](https://atom.io/packages/markdown-preview-enhanced)
|
||||
- [Atom Mermaid](https://atom.io/packages/atom-mermaid)
|
||||
- [Language Mermaid Syntax Highlighter](https://atom.io/packages/language-mermaid)
|
||||
- Atom _(Atom has been [archived.](https://github.blog/2022-06-08-sunsetting-atom/))_
|
||||
- [Markdown Preview Enhanced](https://github.com/shd101wyy/markdown-preview-enhanced)
|
||||
- [Atom Mermaid](https://github.com/y-takey/atom-mermaid)
|
||||
- [Language Mermaid Syntax Highlighter](https://github.com/ytisf/language-mermaid)
|
||||
- [Sublime Text 3](https://sublimetext.com)
|
||||
- [Mermaid Package](https://packagecontrol.io/packages/Mermaid)
|
||||
- [Astah](https://astah.net)
|
9
docs/ecosystem/showcases.md
Normal file
9
docs/ecosystem/showcases.md
Normal file
@ -0,0 +1,9 @@
|
||||
> **Warning**
|
||||
>
|
||||
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
|
||||
>
|
||||
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/ecosystem/showcases.md](../../packages/mermaid/src/docs/ecosystem/showcases.md).
|
||||
|
||||
# Showcases
|
||||
|
||||
- [Swimm - Up-to-date diagrams with Swimm, the knowledge management tool for code](https://docs.swimm.io/Features/diagrams-and-charts).
|
@ -367,7 +367,7 @@ _Unfortunately you can not have a cake and eat it at the same time which in this
|
||||
|
||||
## Reporting vulnerabilities
|
||||
|
||||
To report a vulnerability, please e-mail security@mermaid.live with a description of the issue, the steps you took to create the issue, affected versions, and if known, mitigations for the issue.
|
||||
To report a vulnerability, please e-mail <security@mermaid.live> with a description of the issue, the steps you took to create the issue, affected versions, and if known, mitigations for the issue.
|
||||
|
||||
## Appreciation
|
||||
|
||||
|
@ -79,9 +79,9 @@ Editing is as easy as pasting your **Diagram code**, into the `code` section of
|
||||
|
||||
The Gist you create should have a code.mmd file and optionally a config.json. [Example](https://gist.github.com/sidharthv96/6268a23e673a533dcb198f241fd7012a)
|
||||
|
||||
To load a gist into the Editor, you can use https://mermaid.live/edit?gist=https://gist.github.com/sidharthv96/6268a23e673a533dcb198f241fd7012a
|
||||
To load a gist into the Editor, you can use <https://mermaid.live/edit?gist=https://gist.github.com/sidharthv96/6268a23e673a533dcb198f241fd7012a>
|
||||
|
||||
and to View, https://mermaid.live/view?gist=https://gist.github.com/sidharthv96/6268a23e673a533dcb198f241fd7012a
|
||||
and to View, <https://mermaid.live/view?gist=https://gist.github.com/sidharthv96/6268a23e673a533dcb198f241fd7012a>
|
||||
|
||||
## 2. Using Mermaid Plugins:
|
||||
|
||||
|
@ -130,121 +130,121 @@ The number of shapes per row and the number of boundaries can be adjusted using
|
||||
|
||||
The following unfinished features are not supported in the short term.
|
||||
|
||||
- \[ ] sprite
|
||||
- [ ] sprite
|
||||
|
||||
- \[ ] tags
|
||||
- [ ] tags
|
||||
|
||||
- \[ ] link
|
||||
- [ ] link
|
||||
|
||||
- \[ ] Legend
|
||||
- [ ] Legend
|
||||
|
||||
- \[x] System Context
|
||||
- [x] System Context
|
||||
|
||||
- - \[x] Person(alias, label, ?descr, ?sprite, ?tags, $link)
|
||||
- - [x] Person(alias, label, ?descr, ?sprite, ?tags, $link)
|
||||
|
||||
- - \[x] Person_Ext
|
||||
- - [x] Person_Ext
|
||||
|
||||
- - \[x] System(alias, label, ?descr, ?sprite, ?tags, $link)
|
||||
- - [x] System(alias, label, ?descr, ?sprite, ?tags, $link)
|
||||
|
||||
- - \[x] SystemDb
|
||||
- - [x] SystemDb
|
||||
|
||||
- - \[x] SystemQueue
|
||||
- - [x] SystemQueue
|
||||
|
||||
- - \[x] System_Ext
|
||||
- - [x] System_Ext
|
||||
|
||||
- - \[x] SystemDb_Ext
|
||||
- - [x] SystemDb_Ext
|
||||
|
||||
- - \[x] SystemQueue_Ext
|
||||
- - [x] SystemQueue_Ext
|
||||
|
||||
- - \[x] Boundary(alias, label, ?type, ?tags, $link)
|
||||
- - [x] Boundary(alias, label, ?type, ?tags, $link)
|
||||
|
||||
- - \[x] Enterprise_Boundary(alias, label, ?tags, $link)
|
||||
- - [x] Enterprise_Boundary(alias, label, ?tags, $link)
|
||||
|
||||
- - \[x] System_Boundary
|
||||
- - [x] System_Boundary
|
||||
|
||||
- \[x] Container diagram
|
||||
- [x] Container diagram
|
||||
|
||||
- - \[x] Container(alias, label, ?techn, ?descr, ?sprite, ?tags, $link)
|
||||
- - [x] Container(alias, label, ?techn, ?descr, ?sprite, ?tags, $link)
|
||||
|
||||
- - \[x] ContainerDb
|
||||
- - [x] ContainerDb
|
||||
|
||||
- - \[x] ContainerQueue
|
||||
- - [x] ContainerQueue
|
||||
|
||||
- - \[x] Container_Ext
|
||||
- - [x] Container_Ext
|
||||
|
||||
- - \[x] ContainerDb_Ext
|
||||
- - [x] ContainerDb_Ext
|
||||
|
||||
- - \[x] ContainerQueue_Ext
|
||||
- - [x] ContainerQueue_Ext
|
||||
|
||||
- - \[x] Container_Boundary(alias, label, ?tags, $link)
|
||||
- - [x] Container_Boundary(alias, label, ?tags, $link)
|
||||
|
||||
- \[x] Component diagram
|
||||
- [x] Component diagram
|
||||
|
||||
- - \[x] Component(alias, label, ?techn, ?descr, ?sprite, ?tags, $link)
|
||||
- - [x] Component(alias, label, ?techn, ?descr, ?sprite, ?tags, $link)
|
||||
|
||||
- - \[x] ComponentDb
|
||||
- - [x] ComponentDb
|
||||
|
||||
- - \[x] ComponentQueue
|
||||
- - [x] ComponentQueue
|
||||
|
||||
- - \[x] Component_Ext
|
||||
- - [x] Component_Ext
|
||||
|
||||
- - \[x] ComponentDb_Ext
|
||||
- - [x] ComponentDb_Ext
|
||||
|
||||
- - \[x] ComponentQueue_Ext
|
||||
- - [x] ComponentQueue_Ext
|
||||
|
||||
- \[x] Dynamic diagram
|
||||
- [x] Dynamic diagram
|
||||
|
||||
- - \[x] RelIndex(index, from, to, label, ?tags, $link)
|
||||
- - [x] RelIndex(index, from, to, label, ?tags, $link)
|
||||
|
||||
- \[x] Deployment diagram
|
||||
- [x] Deployment diagram
|
||||
|
||||
- - \[x] Deployment_Node(alias, label, ?type, ?descr, ?sprite, ?tags, $link)
|
||||
- - [x] Deployment_Node(alias, label, ?type, ?descr, ?sprite, ?tags, $link)
|
||||
|
||||
- - \[x] Node(alias, label, ?type, ?descr, ?sprite, ?tags, $link): short name of Deployment_Node()
|
||||
- - [x] Node(alias, label, ?type, ?descr, ?sprite, ?tags, $link): short name of Deployment_Node()
|
||||
|
||||
- - \[x] Node_L(alias, label, ?type, ?descr, ?sprite, ?tags, $link): left aligned Node()
|
||||
- - [x] Node_L(alias, label, ?type, ?descr, ?sprite, ?tags, $link): left aligned Node()
|
||||
|
||||
- - \[x] Node_R(alias, label, ?type, ?descr, ?sprite, ?tags, $link): right aligned Node()
|
||||
- - [x] Node_R(alias, label, ?type, ?descr, ?sprite, ?tags, $link): right aligned Node()
|
||||
|
||||
- \[x] Relationship Types
|
||||
- [x] Relationship Types
|
||||
|
||||
- - \[x] Rel(from, to, label, ?techn, ?descr, ?sprite, ?tags, $link)
|
||||
- - [x] Rel(from, to, label, ?techn, ?descr, ?sprite, ?tags, $link)
|
||||
|
||||
- - \[x] BiRel (bidirectional relationship)
|
||||
- - [x] BiRel (bidirectional relationship)
|
||||
|
||||
- - \[x] Rel_U, Rel_Up
|
||||
- - [x] Rel_U, Rel_Up
|
||||
|
||||
- - \[x] Rel_D, Rel_Down
|
||||
- - [x] Rel_D, Rel_Down
|
||||
|
||||
- - \[x] Rel_L, Rel_Left
|
||||
- - [x] Rel_L, Rel_Left
|
||||
|
||||
- - \[x] Rel_R, Rel_Right
|
||||
- - [x] Rel_R, Rel_Right
|
||||
|
||||
- - \[x] Rel_Back
|
||||
- - [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
|
||||
- [ ] 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.
|
||||
- - [ ] 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.
|
||||
|
||||
- - \[ ] AddRelTag(tagStereo, ?textColor, ?lineColor, ?lineStyle, ?sprite, ?techn, ?legendText, ?legendSprite): Introduces a new Relationship tag. The styles of the tagged relationships are updated and the tag is displayed in the calculated legend.
|
||||
- - [ ] AddRelTag(tagStereo, ?textColor, ?lineColor, ?lineStyle, ?sprite, ?techn, ?legendText, ?legendSprite): Introduces a new Relationship tag. The styles of the tagged relationships are updated and the tag is displayed in the calculated legend.
|
||||
|
||||
- - \[x] UpdateElementStyle(elementName, ?bgColor, ?fontColor, ?borderColor, ?shadowing, ?shape, ?sprite, ?techn, ?legendText, ?legendSprite): This call updates the default style of the elements (component, ...) and creates no additional legend entry.
|
||||
- - [x] UpdateElementStyle(elementName, ?bgColor, ?fontColor, ?borderColor, ?shadowing, ?shape, ?sprite, ?techn, ?legendText, ?legendSprite): This call updates the default style of the elements (component, ...) and creates no additional legend entry.
|
||||
|
||||
- - \[x] UpdateRelStyle(from, to, ?textColor, ?lineColor, ?offsetX, ?offsetY): This call updates the default relationship colors and creates no additional legend entry. Two new parameters, offsetX and offsetY, are added to set the offset of the original position of the text.
|
||||
- - [x] UpdateRelStyle(from, to, ?textColor, ?lineColor, ?offsetX, ?offsetY): This call updates the default relationship colors and creates no additional legend entry. Two new parameters, offsetX and offsetY, are added to set the offset of the original position of the text.
|
||||
|
||||
- - \[ ] RoundedBoxShape(): This call returns the name of the rounded box shape and can be used as ?shape argument.
|
||||
- - [ ] RoundedBoxShape(): This call returns the name of the rounded box shape and can be used as ?shape argument.
|
||||
|
||||
- - \[ ] EightSidedShape(): This call returns the name of the eight sided shape and can be used as ?shape argument.
|
||||
- - [ ] EightSidedShape(): This call returns the name of the eight sided shape and can be used as ?shape argument.
|
||||
|
||||
- - \[ ] DashedLine(): This call returns the name of the dashed line and can be used as ?lineStyle argument.
|
||||
- - [ ] DashedLine(): This call returns the name of the dashed line and can be used as ?lineStyle argument.
|
||||
|
||||
- - \[ ] DottedLine(): This call returns the name of the dotted line and can be used as ?lineStyle argument.
|
||||
- - [ ] DottedLine(): This call returns the name of the dotted line and can be used as ?lineStyle argument.
|
||||
|
||||
- - \[ ] BoldLine(): This call returns the name of the bold line and can be used as ?lineStyle argument.
|
||||
- - [ ] BoldLine(): This call returns the name of the bold line and can be used as ?lineStyle argument.
|
||||
|
||||
- - \[x] UpdateLayoutConfig(?c4ShapeInRow, ?c4BoundaryInRow): New. This call updates the default c4ShapeInRow(4) and c4BoundaryInRow(2).
|
||||
- - [x] UpdateLayoutConfig(?c4ShapeInRow, ?c4BoundaryInRow): New. This call updates the default c4ShapeInRow(4) and c4BoundaryInRow(2).
|
||||
|
||||
There are two ways to assign parameters with question marks. One uses the non-named parameter assignment method in the order of the parameters, and the other uses the named parameter assignment method, where the name must start with a $ symbol.
|
||||
|
||||
|
@ -206,7 +206,7 @@ class BankAccount{
|
||||
|
||||
#### Generic Types
|
||||
|
||||
Members can be defined using generic types, such as `List<int>`, for fields, parameters, and return types by enclosing the type within `~` (**tilde**). Note: **nested** type declarations such as `List<List<int>>` are not currently supported.
|
||||
Members can be defined using generic types, such as `List<int>`, for fields, parameters, and return types by enclosing the type within `~` (**tilde**). **Nested** type declarations such as `List<List<int>>` are supported.
|
||||
|
||||
Generics can be represented as part of a class definition and also in the parameters or the return value of a method/function:
|
||||
|
||||
@ -222,6 +222,7 @@ class Square~Shape~{
|
||||
Square : -List~string~ messages
|
||||
Square : +setMessages(List~string~ messages)
|
||||
Square : +getMessages() List~string~
|
||||
Square : +getDistanceMatrix() List~List~int~~
|
||||
```
|
||||
|
||||
```mermaid
|
||||
@ -236,12 +237,9 @@ class Square~Shape~{
|
||||
Square : -List~string~ messages
|
||||
Square : +setMessages(List~string~ messages)
|
||||
Square : +getMessages() List~string~
|
||||
Square : +getDistanceMatrix() List~List~int~~
|
||||
```
|
||||
|
||||
#### Return Type
|
||||
|
||||
Optionally you can end the method/function definition with the data type that will be returned.
|
||||
|
||||
#### Visibility
|
||||
|
||||
To describe the visibility (or encapsulation) of an attribute or method/function that is a part of a class (i.e. a class member), optional notation may be placed before that members' name:
|
||||
@ -271,7 +269,7 @@ There are eight different types of relations defined for classes under UML which
|
||||
| Type | Description |
|
||||
| ------- | ------------- |
|
||||
| `<\|--` | Inheritance |
|
||||
| `\*--` | Composition |
|
||||
| `*--` | Composition |
|
||||
| `o--` | Aggregation |
|
||||
| `-->` | Association |
|
||||
| `--` | Link (Solid) |
|
||||
|
@ -162,7 +162,7 @@ erDiagram
|
||||
|
||||
### Attributes
|
||||
|
||||
Attributes can be defined for entities by specifying the entity name followed by a block containing multiple `type name` pairs, where a block is delimited by an opening `{` and a closing `}`. For example:
|
||||
Attributes can be defined for entities by specifying the entity name followed by a block containing multiple `type name` pairs, where a block is delimited by an opening `{` and a closing `}`. The attributes are rendered inside the entity boxes. For example:
|
||||
|
||||
```mermaid-example
|
||||
erDiagram
|
||||
@ -196,82 +196,58 @@ erDiagram
|
||||
}
|
||||
```
|
||||
|
||||
The attributes are rendered inside the entity boxes:
|
||||
|
||||
```mermaid-example
|
||||
erDiagram
|
||||
CAR ||--o{ NAMED-DRIVER : allows
|
||||
CAR {
|
||||
string registrationNumber
|
||||
string make
|
||||
string model
|
||||
}
|
||||
PERSON ||--o{ NAMED-DRIVER : is
|
||||
PERSON {
|
||||
string firstName
|
||||
string lastName
|
||||
int age
|
||||
}
|
||||
```
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
CAR ||--o{ NAMED-DRIVER : allows
|
||||
CAR {
|
||||
string registrationNumber
|
||||
string make
|
||||
string model
|
||||
}
|
||||
PERSON ||--o{ NAMED-DRIVER : is
|
||||
PERSON {
|
||||
string firstName
|
||||
string lastName
|
||||
int age
|
||||
}
|
||||
```
|
||||
|
||||
The `type` and `name` values must begin with an alphabetic character and may contain digits, hyphens or underscores. Other than that, there are no restrictions, and there is no implicit set of valid data types.
|
||||
The `type` and `name` values must begin with an alphabetic character and may contain digits, hyphens, underscores, parentheses and square brackets. Other than that, there are no restrictions, and there is no implicit set of valid data types.
|
||||
|
||||
#### Attribute Keys and Comments
|
||||
|
||||
Attributes may also have a `key` or comment defined. Keys can be "PK" or "FK", for Primary Key or Foreign Key. And a `comment` is defined by double quotes at the end of an attribute. Comments themselves cannot have double-quote characters in them.
|
||||
Attributes may also have a `key` or comment defined. Keys can be `PK`, `FK` or `UK`, for Primary Key, Foreign Key or Unique Key. To specify multiple key constraints on a single attribute, separate them with a comma (e.g., `PK, FK`).. A `comment` is defined by double quotes at the end of an attribute. Comments themselves cannot have double-quote characters in them.
|
||||
|
||||
```mermaid-example
|
||||
erDiagram
|
||||
CAR ||--o{ NAMED-DRIVER : allows
|
||||
CAR {
|
||||
string allowedDriver FK "The license of the allowed driver"
|
||||
string registrationNumber
|
||||
string registrationNumber PK
|
||||
string make
|
||||
string model
|
||||
string[] parts
|
||||
}
|
||||
PERSON ||--o{ NAMED-DRIVER : is
|
||||
PERSON {
|
||||
string driversLicense PK "The license #"
|
||||
string firstName
|
||||
string(99) firstName "Only 99 characters are allowed"
|
||||
string lastName
|
||||
string phone UK
|
||||
int age
|
||||
}
|
||||
MANUFACTURER only one to zero or more CAR
|
||||
NAMED-DRIVER {
|
||||
string carRegistrationNumber PK, FK
|
||||
string driverLicence PK, FK
|
||||
}
|
||||
MANUFACTURER only one to zero or more CAR : makes
|
||||
```
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
CAR ||--o{ NAMED-DRIVER : allows
|
||||
CAR {
|
||||
string allowedDriver FK "The license of the allowed driver"
|
||||
string registrationNumber
|
||||
string registrationNumber PK
|
||||
string make
|
||||
string model
|
||||
string[] parts
|
||||
}
|
||||
PERSON ||--o{ NAMED-DRIVER : is
|
||||
PERSON {
|
||||
string driversLicense PK "The license #"
|
||||
string firstName
|
||||
string(99) firstName "Only 99 characters are allowed"
|
||||
string lastName
|
||||
string phone UK
|
||||
int age
|
||||
}
|
||||
MANUFACTURER only one to zero or more CAR
|
||||
NAMED-DRIVER {
|
||||
string carRegistrationNumber PK, FK
|
||||
string driverLicence PK, FK
|
||||
}
|
||||
MANUFACTURER only one to zero or more CAR : makes
|
||||
```
|
||||
|
||||
### Other Things
|
||||
|
@ -842,8 +842,8 @@ In the example below the style defined in the linkStyle statement will belong to
|
||||
### Styling line curves
|
||||
|
||||
It is possible to style the type of curve used for lines between items, if the default method does not meet your needs.
|
||||
Available curve styles include `basis`, `bump`, `linear`, `monotoneX`, `monotoneY`, `natural`, `step`, `stepAfter`,
|
||||
and `stepBefore`.
|
||||
Available curve styles include `basis`, `bumpX`, `bumpY`, `cardinal`, `catmullRom`, `linear`, `monotoneX`, `monotoneY`,
|
||||
`natural`, `step`, `stepAfter`, and `stepBefore`.
|
||||
|
||||
In this example, a left-to-right graph uses the `stepBefore` curve style:
|
||||
|
||||
@ -990,7 +990,22 @@ flowchart LR
|
||||
C -->|Two| E[Result two]
|
||||
```
|
||||
|
||||
## Configuration...
|
||||
## Configuration
|
||||
|
||||
### Renderer
|
||||
|
||||
The layout of the diagram is done with the renderer. The default renderer is dagre.
|
||||
|
||||
Starting with Mermaid version 9.4, you can use an alternate renderer named elk. The elk renderer is better for larger and/or more complex diagrams.
|
||||
|
||||
The _elk_ renderer is an experimenal feature.
|
||||
You can change the renderer to elk by adding this directive:
|
||||
|
||||
%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%
|
||||
|
||||
Note that the site needs to use mermaid version 9.4+ for this to work and have this featured enabled in the lazy-loading configuration.
|
||||
|
||||
### Width
|
||||
|
||||
It is possible to adjust the width of the rendered flowchart.
|
||||
|
||||
|
@ -172,65 +172,72 @@ Final milestone : milestone, m2, 18:14, 2min
|
||||
|
||||
The default input date format is `YYYY-MM-DD`. You can define your custom `dateFormat`.
|
||||
|
||||
dateFormat YYYY-MM-DD
|
||||
```markdown
|
||||
dateFormat YYYY-MM-DD
|
||||
```
|
||||
|
||||
The following formatting options are supported:
|
||||
|
||||
Input Example Description:
|
||||
YYYY 2014 4 digit year
|
||||
YY 14 2 digit year
|
||||
Q 1..4 Quarter of year. Sets month to first month in quarter.
|
||||
M MM 1..12 Month number
|
||||
MMM MMMM January..Dec Month name in locale set by moment.locale()
|
||||
D DD 1..31 Day of month
|
||||
Do 1st..31st Day of month with ordinal
|
||||
DDD DDDD 1..365 Day of year
|
||||
X 1410715640.579 Unix timestamp
|
||||
x 1410715640579 Unix ms timestamp
|
||||
H HH 0..23 24 hour time
|
||||
h hh 1..12 12 hour time used with a A.
|
||||
a A am pm Post or ante meridiem
|
||||
m mm 0..59 Minutes
|
||||
s ss 0..59 Seconds
|
||||
S 0..9 Tenths of a second
|
||||
SS 0..99 Hundreds of a second
|
||||
SSS 0..999 Thousandths of a second
|
||||
Z ZZ +12:00 Offset from UTC as +-HH:mm, +-HHmm, or Z
|
||||
| Input | Example | Description |
|
||||
| ---------- | -------------- | ------------------------------------------------------ |
|
||||
| `YYYY` | 2014 | 4 digit year |
|
||||
| `YY` | 14 | 2 digit year |
|
||||
| `Q` | 1..4 | Quarter of year. Sets month to first month in quarter. |
|
||||
| `M MM` | 1..12 | Month number |
|
||||
| `MMM MMMM` | January..Dec | Month name in locale set by `moment.locale()` |
|
||||
| `D DD` | 1..31 | Day of month |
|
||||
| `Do` | 1st..31st | Day of month with ordinal |
|
||||
| `DDD DDDD` | 1..365 | Day of year |
|
||||
| `X` | 1410715640.579 | Unix timestamp |
|
||||
| `x` | 1410715640579 | Unix ms timestamp |
|
||||
| `H HH` | 0..23 | 24 hour time |
|
||||
| `h hh` | 1..12 | 12 hour time used with `a A`. |
|
||||
| `a A` | am pm | Post or ante meridiem |
|
||||
| `m mm` | 0..59 | Minutes |
|
||||
| `s ss` | 0..59 | Seconds |
|
||||
| `S` | 0..9 | Tenths of a second |
|
||||
| `SS` | 0..99 | Hundreds of a second |
|
||||
| `SSS` | 0..999 | Thousandths of a second |
|
||||
| `Z ZZ` | +12:00 | Offset from UTC as +-HH:mm, +-HHmm, or Z |
|
||||
|
||||
More info in: https://momentjs.com/docs/#/parsing/string-format/
|
||||
More info in: <https://momentjs.com/docs/#/parsing/string-format/>
|
||||
|
||||
### Output date format on the axis
|
||||
|
||||
The default output date format is `YYYY-MM-DD`. You can define your custom `axisFormat`, like `2020-Q1` for the first quarter of the year 2020.
|
||||
|
||||
axisFormat %Y-%m-%d
|
||||
```markdown
|
||||
axisFormat %Y-%m-%d
|
||||
```
|
||||
|
||||
The following formatting strings are supported:
|
||||
|
||||
%a - abbreviated weekday name.
|
||||
%A - full weekday name.
|
||||
%b - abbreviated month name.
|
||||
%B - full month name.
|
||||
%c - date and time, as "%a %b %e %H:%M:%S %Y".
|
||||
%d - zero-padded day of the month as a decimal number [01,31].
|
||||
%e - space-padded day of the month as a decimal number [ 1,31]; equivalent to %_d.
|
||||
%H - hour (24-hour clock) as a decimal number [00,23].
|
||||
%I - hour (12-hour clock) as a decimal number [01,12].
|
||||
%j - day of the year as a decimal number [001,366].
|
||||
%m - month as a decimal number [01,12].
|
||||
%M - minute as a decimal number [00,59].
|
||||
%L - milliseconds as a decimal number [000, 999].
|
||||
%p - either AM or PM.
|
||||
%S - second as a decimal number [00,61].
|
||||
%U - week number of the year (Sunday as the first day of the week) as a decimal number [00,53].
|
||||
%w - weekday as a decimal number [0(Sunday),6].
|
||||
%W - week number of the year (Monday as the first day of the week) as a decimal number [00,53].
|
||||
%x - date, as "%m/%d/%Y".
|
||||
%X - time, as "%H:%M:%S".
|
||||
%y - year without century as a decimal number [00,99].
|
||||
%Y - year with century as a decimal number.
|
||||
%Z - time zone offset, such as "-0700".
|
||||
%% - a literal "%" character.
|
||||
| Format | Definition |
|
||||
| ------ | ------------------------------------------------------------------------------------------ |
|
||||
| %a | abbreviated weekday name |
|
||||
| %A | full weekday name |
|
||||
| %b | abbreviated month name |
|
||||
| %B | full month name |
|
||||
| %c | date and time, as "%a %b %e %H:%M:%S %Y" |
|
||||
| %d | zero-padded day of the month as a decimal number \[01,31] |
|
||||
| %e | space-padded day of the month as a decimal number \[ 1,31]; equivalent to %\_d |
|
||||
| %H | hour (24-hour clock) as a decimal number \[00,23] |
|
||||
| %I | hour (12-hour clock) as a decimal number \[01,12] |
|
||||
| %j | day of the year as a decimal number \[001,366] |
|
||||
| %m | month as a decimal number \[01,12] |
|
||||
| %M | minute as a decimal number \[00,59] |
|
||||
| %L | milliseconds as a decimal number \[000, 999] |
|
||||
| %p | either AM or PM |
|
||||
| %S | second as a decimal number \[00,61] |
|
||||
| %U | week number of the year (Sunday as the first day of the week) as a decimal number \[00,53] |
|
||||
| %w | weekday as a decimal number \[0(Sunday),6] |
|
||||
| %W | week number of the year (Monday as the first day of the week) as a decimal number \[00,53] |
|
||||
| %x | date, as "%m/%d/%Y" |
|
||||
| %X | time, as "%H:%M:%S" |
|
||||
| %y | year without century as a decimal number \[00,99] |
|
||||
| %Y | year with century as a decimal number |
|
||||
| %Z | time zone offset, such as "-0700" |
|
||||
| %% | a literal "%" character |
|
||||
|
||||
More info in: <https://github.com/d3/d3-time-format/tree/v4.0.0#locale_format>
|
||||
|
||||
@ -238,11 +245,15 @@ More info in: <https://github.com/d3/d3-time-format/tree/v4.0.0#locale_format>
|
||||
|
||||
The default output ticks are auto. You can custom your `tickInterval`, like `1day` or `1week`.
|
||||
|
||||
tickInterval 1day
|
||||
```markdown
|
||||
tickInterval 1day
|
||||
```
|
||||
|
||||
The pattern is:
|
||||
|
||||
/^([1-9][0-9]*)(minute|hour|day|week|month)$/
|
||||
```javascript
|
||||
/^([1-9][0-9]*)(minute|hour|day|week|month)$/;
|
||||
```
|
||||
|
||||
More info in: <https://github.com/d3/d3-time#interval_every>
|
||||
|
||||
|
@ -88,7 +88,7 @@ In this way we can use a text outline to generate a hierarchical mindmap.
|
||||
|
||||
## Different shapes
|
||||
|
||||
Mermaids mindmaps can show node using different shapes. When specifying a shape for a node the syntax for the is similar to flowchart nodes, with an id followed by the shape definition and with the text within the shape delimiters. Where possible we try/will try to keep the same shapes as for flowcharts even though they are not all supported from the start.
|
||||
Mermaid mindmaps can show nodes using different shapes. When specifying a shape for a node the syntax is similar to flowchart nodes, with an id followed by the shape definition and with the text within the shape delimiters. Where possible we try/will try to keep the same shapes as for flowcharts, even though they are not all supported from the start.
|
||||
|
||||
Mindmap can show the following shapes:
|
||||
|
||||
|
@ -94,6 +94,59 @@ sequenceDiagram
|
||||
J->>A: Great!
|
||||
```
|
||||
|
||||
### Grouping / Box
|
||||
|
||||
The actor(s) can be grouped in vertical boxes. You can define a color (if not, it will be transparent) and/or a descriptive label using the following notation:
|
||||
|
||||
box Aqua Group Description
|
||||
... actors ...
|
||||
end
|
||||
box Group without description
|
||||
... actors ...
|
||||
end
|
||||
box rgb(33,66,99)
|
||||
... actors ...
|
||||
end
|
||||
|
||||
> **Note**
|
||||
> If your group name is a color you can force the color to be transparent:
|
||||
|
||||
box transparent Aqua
|
||||
... actors ...
|
||||
end
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
box Purple Alice & John
|
||||
participant A
|
||||
participant J
|
||||
end
|
||||
box Another Group
|
||||
participant B
|
||||
participant C
|
||||
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?
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
box Purple Alice & John
|
||||
participant A
|
||||
participant J
|
||||
end
|
||||
box Another Group
|
||||
participant B
|
||||
participant C
|
||||
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?
|
||||
```
|
||||
|
||||
## Messages
|
||||
|
||||
Messages can be of two displayed either solid or with a dotted line.
|
||||
@ -102,16 +155,16 @@ Messages can be of two displayed either solid or with a dotted line.
|
||||
|
||||
There are six types of arrows currently supported:
|
||||
|
||||
| Type | Description |
|
||||
| ---- | ------------------------------------------------ |
|
||||
| -> | Solid line without arrow |
|
||||
| --> | Dotted line without arrow |
|
||||
| ->> | Solid line with arrowhead |
|
||||
| -->> | Dotted line with arrowhead |
|
||||
| -x | Solid line with a cross at the end |
|
||||
| --x | Dotted line with a cross at the end. |
|
||||
| -) | Solid line with an open arrow at the end (async) |
|
||||
| --) | Dotted line with a open arrow at the end (async) |
|
||||
| Type | Description |
|
||||
| ------ | ------------------------------------------------ |
|
||||
| `->` | Solid line without arrow |
|
||||
| `-->` | Dotted line without arrow |
|
||||
| `->>` | Solid line with arrowhead |
|
||||
| `-->>` | Dotted line with arrowhead |
|
||||
| `-x` | Solid line with a cross at the end |
|
||||
| `--x` | Dotted line with a cross at the end. |
|
||||
| `-)` | Solid line with an open arrow at the end (async) |
|
||||
| `--)` | Dotted line with a open arrow at the end (async) |
|
||||
|
||||
## Activations
|
||||
|
||||
@ -198,6 +251,20 @@ sequenceDiagram
|
||||
Note over Alice,John: A typical interaction
|
||||
```
|
||||
|
||||
It is also possible to add a line break (applies to text input in general):
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
Alice->John: Hello John, how are you?
|
||||
Note over Alice,John: A typical interaction<br/>But now in two lines
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
Alice->John: Hello John, how are you?
|
||||
Note over Alice,John: A typical interaction<br/>But now in two lines
|
||||
```
|
||||
|
||||
## Loops
|
||||
|
||||
It is possible to express loops in a sequence diagram. This is done by the notation
|
||||
|
462
docs/syntax/timeline.md
Normal file
462
docs/syntax/timeline.md
Normal file
@ -0,0 +1,462 @@
|
||||
> **Warning**
|
||||
>
|
||||
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
|
||||
>
|
||||
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/syntax/timeline.md](../../packages/mermaid/src/docs/syntax/timeline.md).
|
||||
|
||||
# Timeline Diagram
|
||||
|
||||
> 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. 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
|
||||
|
||||
### An example of a timeline.
|
||||
|
||||
```mermaid-example
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook
|
||||
: Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
```
|
||||
|
||||
```mermaid
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook
|
||||
: Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
```
|
||||
|
||||
## Syntax
|
||||
|
||||
The syntax for creating Timeline diagram is simple. You always start with the `timeline` keyword to let mermaid know that you want to create a timeline diagram.
|
||||
|
||||
After that there is a possibility to add a title to the timeline. This is done by adding a line with the keyword `title` followed by the title text.
|
||||
|
||||
Then you add the timeline data, where you always start with a time period, followed by a colon and then the text for the event. Optionally you can add a second colon and then the text for the event. So, you can have one or more events per time period.
|
||||
|
||||
```json
|
||||
{time period} : {event}
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```json
|
||||
{time period} : {event} : {event}
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```json
|
||||
{time period} : {event}
|
||||
: {event}
|
||||
: {event}
|
||||
```
|
||||
|
||||
NOTE: Both time period and event are simple text, and not limited to numbers.
|
||||
|
||||
Let us look at the syntax for the example above.
|
||||
|
||||
```mermaid-example
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
```
|
||||
|
||||
```mermaid
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
```
|
||||
|
||||
In this way we can use a text outline to generate a timeline diagram.
|
||||
The sequence of time period and events is important, as it will be used to draw the timeline. The first time period will be placed at the left side of the timeline, and the last time period will be placed at the right side of the timeline.
|
||||
|
||||
Similarly, the first event will be placed at the top for that specific time period, and the last event will be placed at the bottom.
|
||||
|
||||
## Grouping of time periods in sections/ages
|
||||
|
||||
You can group time periods in sections/ages. This is done by adding a line with the keyword `section` followed by the section name.
|
||||
|
||||
All subsequent time periods will be placed in this section until a new section is defined.
|
||||
|
||||
If no section is defined, all time periods will be placed in the default section.
|
||||
|
||||
Let us look at an example, where we have grouped the time periods in sections.
|
||||
|
||||
```mermaid-example
|
||||
timeline
|
||||
title Timeline of Industrial Revolution
|
||||
section 17th-20th century
|
||||
Industry 1.0 : Machinery, Water power, Steam <br>power
|
||||
Industry 2.0 : Electricity, Internal combustion engine, Mass production
|
||||
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
|
||||
```
|
||||
|
||||
```mermaid
|
||||
timeline
|
||||
title Timeline of Industrial Revolution
|
||||
section 17th-20th century
|
||||
Industry 1.0 : Machinery, Water power, Steam <br>power
|
||||
Industry 2.0 : Electricity, Internal combustion engine, Mass production
|
||||
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
|
||||
```
|
||||
|
||||
As you can see, the time periods are placed in the sections, and the sections are placed in the order they are defined.
|
||||
|
||||
All time periods and events under a given section follow a similar color scheme. This is done to make it easier to see the relationship between time periods and events.
|
||||
|
||||
## Wrapping of text for long time-periods or events
|
||||
|
||||
By default, the text for time-periods and events will be wrapped if it is too long. This is done to avoid that the text is drawn outside the diagram.
|
||||
|
||||
You can also use `<br>` to force a line break.
|
||||
|
||||
Let us look at another example, where we have a long time period, and a long event.
|
||||
|
||||
```mermaid-example
|
||||
timeline
|
||||
title England's History Timeline
|
||||
section Stone Age
|
||||
7600 BC : Britain's oldest known house was built in Orkney, Scotland
|
||||
6000 BC : Sea levels rise and Britain becomes an island.<br> The people who live here are hunter-gatherers.
|
||||
section Broze Age
|
||||
2300 BC : People arrive from Europe and settle in Britain. <br>They bring farming and metalworking.
|
||||
: New styles of pottery and ways of burying the dead appear.
|
||||
2200 BC : The last major building works are completed at Stonehenge.<br> People now bury their dead in stone circles.
|
||||
: The first metal objects are made in Britain.Some other nice things happen. it is a good time to be alive.
|
||||
|
||||
```
|
||||
|
||||
```mermaid
|
||||
timeline
|
||||
title England's History Timeline
|
||||
section Stone Age
|
||||
7600 BC : Britain's oldest known house was built in Orkney, Scotland
|
||||
6000 BC : Sea levels rise and Britain becomes an island.<br> The people who live here are hunter-gatherers.
|
||||
section Broze Age
|
||||
2300 BC : People arrive from Europe and settle in Britain. <br>They bring farming and metalworking.
|
||||
: New styles of pottery and ways of burying the dead appear.
|
||||
2200 BC : The last major building works are completed at Stonehenge.<br> People now bury their dead in stone circles.
|
||||
: The first metal objects are made in Britain.Some other nice things happen. it is a good time to be alive.
|
||||
|
||||
```
|
||||
|
||||
```mermaid-example
|
||||
timeline
|
||||
title MermaidChart 2023 Timeline
|
||||
section 2023 Q1 <br> Release Personal Tier
|
||||
Buttet 1 : sub-point 1a : sub-point 1b
|
||||
: sub-point 1c
|
||||
Bullet 2 : sub-point 2a : sub-point 2b
|
||||
section 2023 Q2 <br> Release XYZ Tier
|
||||
Buttet 3 : sub-point <br> 3a : sub-point 3b
|
||||
: sub-point 3c
|
||||
Bullet 4 : sub-point 4a : sub-point 4b
|
||||
```
|
||||
|
||||
```mermaid
|
||||
timeline
|
||||
title MermaidChart 2023 Timeline
|
||||
section 2023 Q1 <br> Release Personal Tier
|
||||
Buttet 1 : sub-point 1a : sub-point 1b
|
||||
: sub-point 1c
|
||||
Bullet 2 : sub-point 2a : sub-point 2b
|
||||
section 2023 Q2 <br> Release XYZ Tier
|
||||
Buttet 3 : sub-point <br> 3a : sub-point 3b
|
||||
: sub-point 3c
|
||||
Bullet 4 : sub-point 4a : sub-point 4b
|
||||
```
|
||||
|
||||
## Styling of time periods and events
|
||||
|
||||
As explained earlier, each section has a color scheme, and each time period and event under a section follow the similar color scheme.
|
||||
|
||||
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.
|
||||
|
||||
```mermaid-example
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
|
||||
```
|
||||
|
||||
```mermaid
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
|
||||
```
|
||||
|
||||
Note that this is no, section 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.
|
||||
|
||||
You will need to add this option either via mermaid.intialize function or directives.
|
||||
|
||||
```javascript
|
||||
mermaid.initialize({
|
||||
theme: 'base',
|
||||
startOnLoad: true,
|
||||
logLevel: 0,
|
||||
timeline: {
|
||||
disableMulticolor: false,
|
||||
},
|
||||
...
|
||||
...
|
||||
```
|
||||
|
||||
let us look at same example, where we have disabled the multiColor option.
|
||||
|
||||
```mermaid-example
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'base', 'timeline': {'disableMulticolor': true}}}%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
|
||||
```
|
||||
|
||||
```mermaid
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'base', 'timeline': {'disableMulticolor': true}}}%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
|
||||
```
|
||||
|
||||
### Customizing Color scheme
|
||||
|
||||
You can customize the color scheme using the `cScale0` to `cScale11` theme variables. Mermaid allows you to set unique colors for up-to 12, where `cScale0` variable will drive the value of the first section or time-period, `cScale1` will drive the value of the second section and so on.
|
||||
In case you have more than 12 sections, the color scheme will start to repeat.
|
||||
|
||||
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:
|
||||
|
||||
Now let's override the default values for the `cScale0` to `cScale2` variables:
|
||||
|
||||
```mermaid-example
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': {
|
||||
'cScale0': '#ff0000',
|
||||
'cScale1': '#00ff00',
|
||||
'cScale2': '#0000ff'
|
||||
} } }%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
2007 : Tumblr
|
||||
2008 : Instagram
|
||||
2010 : Pinterest
|
||||
|
||||
```
|
||||
|
||||
```mermaid
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': {
|
||||
'cScale0': '#ff0000',
|
||||
'cScale1': '#00ff00',
|
||||
'cScale2': '#0000ff'
|
||||
} } }%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
2007 : Tumblr
|
||||
2008 : Instagram
|
||||
2010 : Pinterest
|
||||
|
||||
```
|
||||
|
||||
See how the colors are changed to the values specified in the theme variables.
|
||||
|
||||
## 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).
|
||||
|
||||
The following are the different pre-defined theme options:
|
||||
|
||||
- `base`
|
||||
- `forest`
|
||||
- `dark`
|
||||
- `default`
|
||||
- `neutral`
|
||||
|
||||
**NOTE**: To change theme you can either use the `initialize` call or _directives_. Learn more about [directives](../config/directives.md)
|
||||
Let's put them to use, and see how our sample diagram looks in different themes:
|
||||
|
||||
### Base Theme
|
||||
|
||||
```mermaid-example
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'base' } }%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
2007 : Tumblr
|
||||
2008 : Instagram
|
||||
2010 : Pinterest
|
||||
```
|
||||
|
||||
```mermaid
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'base' } }%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
2007 : Tumblr
|
||||
2008 : Instagram
|
||||
2010 : Pinterest
|
||||
```
|
||||
|
||||
### Forest Theme
|
||||
|
||||
```mermaid-example
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'forest' } }%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
2007 : Tumblr
|
||||
2008 : Instagram
|
||||
2010 : Pinterest
|
||||
```
|
||||
|
||||
```mermaid
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'forest' } }%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
2007 : Tumblr
|
||||
2008 : Instagram
|
||||
2010 : Pinterest
|
||||
```
|
||||
|
||||
### Dark Theme
|
||||
|
||||
```mermaid-example
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'dark' } }%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
2007 : Tumblr
|
||||
2008 : Instagram
|
||||
2010 : Pinterest
|
||||
```
|
||||
|
||||
```mermaid
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'dark' } }%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
2007 : Tumblr
|
||||
2008 : Instagram
|
||||
2010 : Pinterest
|
||||
```
|
||||
|
||||
### Default Theme
|
||||
|
||||
```mermaid-example
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'default' } }%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
2007 : Tumblr
|
||||
2008 : Instagram
|
||||
2010 : Pinterest
|
||||
```
|
||||
|
||||
```mermaid
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'default' } }%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
2007 : Tumblr
|
||||
2008 : Instagram
|
||||
2010 : Pinterest
|
||||
```
|
||||
|
||||
### Neutral Theme
|
||||
|
||||
```mermaid-example
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'neutral' } }%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
2007 : Tumblr
|
||||
2008 : Instagram
|
||||
2010 : Pinterest
|
||||
```
|
||||
|
||||
```mermaid
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'neutral' } }%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
2002 : LinkedIn
|
||||
2004 : Facebook : Google
|
||||
2005 : Youtube
|
||||
2006 : Twitter
|
||||
2007 : Tumblr
|
||||
2008 : Instagram
|
||||
2010 : Pinterest
|
||||
```
|
||||
|
||||
You can also refer the implementation in the live editor [here](https://github.com/mermaid-js/mermaid-live-editor/blob/fcf53c98c25604c90a218104268c339be53035a6/src/lib/util/mermaid.ts) to see how the async loading is done.
|
26
package.json
26
package.json
@ -1,10 +1,10 @@
|
||||
{
|
||||
"name": "mermaid-monorepo",
|
||||
"private": true,
|
||||
"version": "9.3.0-rc1",
|
||||
"version": "9.4.0",
|
||||
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
|
||||
"type": "module",
|
||||
"packageManager": "pnpm@7.17.1",
|
||||
"packageManager": "pnpm@7.25.1",
|
||||
"keywords": [
|
||||
"diagram",
|
||||
"markdown",
|
||||
@ -18,12 +18,12 @@
|
||||
"build:vite": "ts-node-esm --transpileOnly .vite/build.ts",
|
||||
"build:mermaid": "pnpm build:vite --mermaid",
|
||||
"build:viz": "pnpm build:mermaid --visualize",
|
||||
"build:types": "tsc -p ./packages/mermaid/tsconfig.json --emitDeclarationOnly && tsc -p ./packages/mermaid-mindmap/tsconfig.json --emitDeclarationOnly",
|
||||
"build:types": "tsc -p ./packages/mermaid/tsconfig.json --emitDeclarationOnly && tsc -p ./packages/mermaid-example-diagram/tsconfig.json --emitDeclarationOnly",
|
||||
"build:watch": "pnpm build:vite --watch",
|
||||
"build": "pnpm run -r clean && concurrently \"pnpm build:vite\" \"pnpm build:types\"",
|
||||
"dev": "concurrently \"pnpm build:vite --watch\" \"ts-node-esm .vite/server.ts\"",
|
||||
"release": "pnpm build",
|
||||
"lint": "eslint --cache --ignore-path .gitignore . && pnpm lint:jison && prettier --check .",
|
||||
"lint": "eslint --cache --cache-strategy content --ignore-path .gitignore . && pnpm lint:jison && prettier --cache --check .",
|
||||
"lint:fix": "eslint --fix --ignore-path .gitignore . && prettier --write . && ts-node-esm scripts/fixCSpell.ts",
|
||||
"lint:jison": "ts-node-esm ./scripts/jison/lint.mts",
|
||||
"cypress": "cypress run",
|
||||
@ -67,17 +67,17 @@
|
||||
"@types/node": "^18.11.9",
|
||||
"@types/prettier": "^2.7.1",
|
||||
"@types/rollup-plugin-visualizer": "^4.2.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.42.1",
|
||||
"@typescript-eslint/parser": "^5.42.1",
|
||||
"@vitest/coverage-c8": "^0.25.1",
|
||||
"@vitest/ui": "^0.25.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.48.2",
|
||||
"@typescript-eslint/parser": "^5.48.2",
|
||||
"@vitest/coverage-c8": "^0.27.0",
|
||||
"@vitest/ui": "^0.27.0",
|
||||
"concurrently": "^7.5.0",
|
||||
"coveralls": "^3.1.1",
|
||||
"cypress": "^10.11.0",
|
||||
"cypress-image-snapshot": "^4.0.1",
|
||||
"esbuild": "^0.15.13",
|
||||
"eslint": "^8.27.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"esbuild": "^0.17.0",
|
||||
"eslint": "^8.32.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-plugin-cypress": "^2.12.1",
|
||||
"eslint-plugin-html": "^7.1.0",
|
||||
"eslint-plugin-jest": "^27.1.5",
|
||||
@ -106,9 +106,9 @@
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.8.4",
|
||||
"vite": "^3.2.3",
|
||||
"vitest": "^0.25.3"
|
||||
"vitest": "^0.27.1"
|
||||
},
|
||||
"volta": {
|
||||
"node": "18.12.1"
|
||||
"node": "18.13.0"
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +0,0 @@
|
||||
### Do not refer this package. It is not ready.
|
||||
|
||||
### Refer mermaid-mindmap instead.
|
@ -1,36 +1,25 @@
|
||||
{
|
||||
"name": "@mermaid-js/mermaid-example-diagram",
|
||||
"version": "9.2.0-rc2",
|
||||
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
|
||||
"main": "dist/mermaid-mindmap.core.mjs",
|
||||
"module": "dist/mermaid-mindmap.core.mjs",
|
||||
"version": "9.3.0",
|
||||
"description": "Example of external diagram module for MermaidJS.",
|
||||
"module": "dist/mermaid-example-diagram.core.mjs",
|
||||
"types": "dist/detector.d.ts",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"require": "./dist/mermaid-example-diagram.min.js",
|
||||
"import": "./dist/mermaid-example-diagram.core.mjs"
|
||||
"import": "./dist/mermaid-example-diagram.core.mjs",
|
||||
"types": "./dist/detector.d.ts"
|
||||
},
|
||||
"./*": "./*"
|
||||
},
|
||||
"keywords": [
|
||||
"diagram",
|
||||
"markdown",
|
||||
"mindmap",
|
||||
"example",
|
||||
"mermaid"
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "rimraf dist",
|
||||
"build:types": "tsc -p ./tsconfig.json --emitDeclarationOnly",
|
||||
"build:watch": "yarn build:code --watch",
|
||||
"build:esbuild": "concurrently \"yarn build:code\" \"yarn build:types\"",
|
||||
"build": "yarn clean; yarn build:esbuild",
|
||||
"dev": "node .esbuild/serve.cjs",
|
||||
"release": "yarn build",
|
||||
"lint": "eslint --cache --ignore-path .gitignore . && yarn lint:jison && prettier --check .",
|
||||
"lint:fix": "eslint --fix --ignore-path .gitignore . && prettier --write .",
|
||||
"lint:jison": "ts-node-esm src/jison/lint.mts",
|
||||
"todo-prepare": "concurrently \"husky install ../../.husky\" \"yarn build\"",
|
||||
"todo-pre-commit": "lint-staged"
|
||||
"prepublishOnly": "pnpm -w run build"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -48,9 +37,19 @@
|
||||
"page"
|
||||
]
|
||||
},
|
||||
"dependencies": {},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^6.0.0",
|
||||
"cytoscape": "^3.23.0",
|
||||
"cytoscape-cose-bilkent": "^4.1.0",
|
||||
"cytoscape-fcose": "^2.1.0",
|
||||
"d3": "^7.0.0",
|
||||
"khroma": "^2.0.0",
|
||||
"non-layered-tidy-tree-layout": "^2.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cytoscape": "^3.19.9",
|
||||
"concurrently": "^7.5.0",
|
||||
"mermaid": "workspace:*",
|
||||
"rimraf": "^3.0.2"
|
||||
},
|
||||
"resolutions": {
|
||||
|
@ -1,18 +1,20 @@
|
||||
// @ts-ignore: TODO Fix ts errors
|
||||
export const id = 'example-diagram';
|
||||
import type { ExternalDiagramDefinition } from 'mermaid';
|
||||
|
||||
/**
|
||||
* Detector function that will be called by mermaid to determine if the diagram is this type of diagram.
|
||||
*
|
||||
* @param txt - The diagram text will be passed to the detector
|
||||
* @returns True if the diagram text matches a diagram of this type
|
||||
*/
|
||||
const id = 'example-diagram';
|
||||
|
||||
export const detector = (txt: string) => {
|
||||
const detector = (txt: string) => {
|
||||
return txt.match(/^\s*example-diagram/) !== null;
|
||||
};
|
||||
|
||||
export const loadDiagram = async () => {
|
||||
const loader = async () => {
|
||||
const { diagram } = await import('./diagram-definition');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
const plugin: ExternalDiagramDefinition = {
|
||||
id,
|
||||
detector,
|
||||
loader,
|
||||
};
|
||||
|
||||
export default plugin;
|
||||
|
@ -12,5 +12,3 @@ export const diagram = {
|
||||
styles,
|
||||
injectUtils,
|
||||
};
|
||||
|
||||
export { detector, id } from './detector';
|
||||
|
@ -1,5 +1,17 @@
|
||||
import { parser } from './parser/exampleDiagram';
|
||||
import db from './exampleDiagramDb';
|
||||
import * as db from './exampleDiagramDb';
|
||||
import { injectUtils } from './mermaidUtils';
|
||||
// Todo fix utils functions for tests
|
||||
import {
|
||||
log,
|
||||
setLogLevel,
|
||||
getConfig,
|
||||
sanitizeText,
|
||||
setupGraphViewBox,
|
||||
} from '../../mermaid/src/diagram-api/diagramAPI';
|
||||
|
||||
injectUtils(log, setLogLevel, getConfig, sanitizeText, setupGraphViewBox);
|
||||
|
||||
describe('when parsing an info graph it', function () {
|
||||
let ex;
|
||||
beforeEach(function () {
|
||||
|
@ -1,4 +1,8 @@
|
||||
const warning = () => null;
|
||||
const warning = (s: string) => {
|
||||
// Todo remove debug code
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('Log function was called before initialization', s);
|
||||
};
|
||||
|
||||
export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
||||
|
||||
@ -19,12 +23,11 @@ export const log: Record<keyof typeof LEVELS, typeof console.log> = {
|
||||
error: warning,
|
||||
fatal: warning,
|
||||
};
|
||||
|
||||
export let setLogLevel: (level: keyof typeof LEVELS | number | string) => void;
|
||||
export let getConfig: () => object;
|
||||
export let sanitizeText: (str: string) => string;
|
||||
/**
|
||||
* Placeholder for the real function that will be injected by mermaid.
|
||||
*/
|
||||
export let commonDb: () => object;
|
||||
// eslint-disable @typescript-eslint/no-explicit-any
|
||||
export let setupGraphViewbox: (
|
||||
graph: any,
|
||||
@ -33,23 +36,15 @@ export let setupGraphViewbox: (
|
||||
useMaxWidth: boolean
|
||||
) => void;
|
||||
|
||||
/**
|
||||
* Function called by mermaid that injects utility functions that help the diagram to be a good citizen.
|
||||
*
|
||||
* @param _log - log from mermaid/src/diagramAPI.ts
|
||||
* @param _setLogLevel - setLogLevel from mermaid/src/diagramAPI.ts
|
||||
* @param _getConfig - getConfig from mermaid/src/diagramAPI.ts
|
||||
* @param _sanitizeText - sanitizeText from mermaid/src/diagramAPI.ts
|
||||
* @param _setupGraphViewbox - setupGraphViewbox from mermaid/src/diagramAPI.ts
|
||||
*/
|
||||
export const injectUtils = (
|
||||
_log: Record<keyof typeof LEVELS, typeof console.log>,
|
||||
_setLogLevel: typeof setLogLevel,
|
||||
_getConfig: typeof getConfig,
|
||||
_sanitizeText: typeof sanitizeText,
|
||||
_setupGraphViewbox: typeof setupGraphViewbox
|
||||
_setLogLevel: any,
|
||||
_getConfig: any,
|
||||
_sanitizeText: any,
|
||||
_setupGraphViewbox: any,
|
||||
_commonDb: any
|
||||
) => {
|
||||
_log.debug('Mermaid utils injected into example-diagram');
|
||||
_log.info('Mermaid utils injected');
|
||||
log.trace = _log.trace;
|
||||
log.debug = _log.debug;
|
||||
log.info = _log.info;
|
||||
@ -60,4 +55,5 @@ export const injectUtils = (
|
||||
getConfig = _getConfig;
|
||||
sanitizeText = _sanitizeText;
|
||||
setupGraphViewbox = _setupGraphViewbox;
|
||||
commonDb = _commonDb;
|
||||
};
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"module": "esnext",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./dist"
|
||||
|
@ -1,64 +0,0 @@
|
||||
{
|
||||
"name": "@mermaid-js/mermaid-mindmap",
|
||||
"version": "9.3.0",
|
||||
"description": "Mindmap diagram module for MermaidJS.",
|
||||
"module": "dist/mermaid-mindmap.core.mjs",
|
||||
"types": "dist/detector.d.ts",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/mermaid-mindmap.core.mjs",
|
||||
"types": "./dist/detector.d.ts"
|
||||
},
|
||||
"./*": "./*"
|
||||
},
|
||||
"keywords": [
|
||||
"diagram",
|
||||
"markdown",
|
||||
"mindmap",
|
||||
"mermaid"
|
||||
],
|
||||
"scripts": {
|
||||
"prepublishOnly": "pnpm -w run build"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mermaid-js/mermaid"
|
||||
},
|
||||
"author": "Knut Sveidqvist",
|
||||
"license": "MIT",
|
||||
"standard": {
|
||||
"ignore": [
|
||||
"**/parser/*.js",
|
||||
"dist/**/*.js",
|
||||
"cypress/**/*.js"
|
||||
],
|
||||
"globals": [
|
||||
"page"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^6.0.0",
|
||||
"cytoscape": "^3.23.0",
|
||||
"cytoscape-cose-bilkent": "^4.1.0",
|
||||
"cytoscape-fcose": "^2.1.0",
|
||||
"d3": "^7.0.0",
|
||||
"khroma": "^2.0.0",
|
||||
"non-layered-tidy-tree-layout": "^2.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"concurrently": "^7.5.0",
|
||||
"mermaid": "workspace:*",
|
||||
"rimraf": "^3.0.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"d3": "^7.0.0"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"sideEffects": [
|
||||
"**/*.css",
|
||||
"**/*.scss"
|
||||
]
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
const warning = (s: string) => {
|
||||
// Todo remove debug code
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('Log function was called before initialization', s);
|
||||
};
|
||||
|
||||
export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
||||
|
||||
export const LEVELS: Record<LogLevel, number> = {
|
||||
trace: 0,
|
||||
debug: 1,
|
||||
info: 2,
|
||||
warn: 3,
|
||||
error: 4,
|
||||
fatal: 5,
|
||||
};
|
||||
|
||||
export const log: Record<keyof typeof LEVELS, typeof console.log> = {
|
||||
trace: warning,
|
||||
debug: warning,
|
||||
info: warning,
|
||||
warn: warning,
|
||||
error: warning,
|
||||
fatal: warning,
|
||||
};
|
||||
|
||||
export let setLogLevel: (level: keyof typeof LEVELS | number | string) => void;
|
||||
export let getConfig: () => object;
|
||||
export let sanitizeText: (str: string) => string;
|
||||
// eslint-disable @typescript-eslint/no-explicit-any
|
||||
export let setupGraphViewbox: (
|
||||
graph: any,
|
||||
svgElem: any,
|
||||
padding: any,
|
||||
useMaxWidth: boolean
|
||||
) => void;
|
||||
|
||||
export const injectUtils = (
|
||||
_log: Record<keyof typeof LEVELS, typeof console.log>,
|
||||
_setLogLevel: any,
|
||||
_getConfig: any,
|
||||
_sanitizeText: any,
|
||||
_setupGraphViewbox: any
|
||||
) => {
|
||||
_log.info('Mermaid utils injected');
|
||||
log.trace = _log.trace;
|
||||
log.debug = _log.debug;
|
||||
log.info = _log.info;
|
||||
log.warn = _log.warn;
|
||||
log.error = _log.error;
|
||||
log.fatal = _log.fatal;
|
||||
setLogLevel = _setLogLevel;
|
||||
getConfig = _getConfig;
|
||||
sanitizeText = _sanitizeText;
|
||||
setupGraphViewbox = _setupGraphViewbox;
|
||||
};
|
@ -1,10 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"module": "esnext",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"include": ["./src/**/*.ts"],
|
||||
"typeRoots": ["./src/types"]
|
||||
}
|
@ -10,7 +10,7 @@
|
||||
|
||||
**感谢所有参与进来提交 PR,解答疑问的人们! 🙏**
|
||||
|
||||
<a href="https://mermaid-js.github.io/mermaid/landing/"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/img/book-banner-pre-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.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>
|
||||
|
||||
## 关于 Mermaid
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mermaid",
|
||||
"version": "9.3.0",
|
||||
"version": "9.4.0",
|
||||
"description": "Markdown-ish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
|
||||
"main": "./dist/mermaid.min.js",
|
||||
"module": "./dist/mermaid.core.mjs",
|
||||
@ -53,17 +53,23 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^6.0.0",
|
||||
"cytoscape": "^3.23.0",
|
||||
"cytoscape-cose-bilkent": "^4.1.0",
|
||||
"cytoscape-fcose": "^2.1.0",
|
||||
"d3": "^7.0.0",
|
||||
"dagre-d3-es": "7.0.6",
|
||||
"dompurify": "2.4.1",
|
||||
"dagre-d3-es": "7.0.8",
|
||||
"dompurify": "2.4.3",
|
||||
"elkjs": "^0.8.2",
|
||||
"khroma": "^2.0.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"moment-mini": "^2.24.0",
|
||||
"moment": "^2.29.4",
|
||||
"non-layered-tidy-tree-layout": "^2.0.2",
|
||||
"stylis": "^4.1.2",
|
||||
"ts-dedent": "^2.2.0",
|
||||
"uuid": "^9.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cytoscape": "^3.19.9",
|
||||
"@types/d3": "^7.4.0",
|
||||
"@types/dompurify": "^2.4.0",
|
||||
"@types/jsdom": "^20.0.1",
|
||||
@ -84,10 +90,11 @@
|
||||
"js-base64": "^3.7.2",
|
||||
"jsdom": "^20.0.2",
|
||||
"micromatch": "^4.0.5",
|
||||
"moment": "^2.29.4",
|
||||
"path-browserify": "^1.0.1",
|
||||
"prettier": "^2.7.1",
|
||||
"remark": "^14.0.2",
|
||||
"remark-frontmatter": "^4.0.1",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"start-server-and-test": "^1.14.0",
|
||||
"typedoc": "^0.23.18",
|
||||
|
@ -3,9 +3,10 @@ import { log } from './logger';
|
||||
import { getDiagram, registerDiagram } from './diagram-api/diagramAPI';
|
||||
import { detectType, getDiagramLoader } from './diagram-api/detectType';
|
||||
import { extractFrontMatter } from './diagram-api/frontmatter';
|
||||
import { isDetailedError, type DetailedError } from './utils';
|
||||
import { isDetailedError } from './utils';
|
||||
import type { DetailedError } from './utils';
|
||||
|
||||
export type ParseErrorFunction = (err: string | DetailedError, hash?: any) => void;
|
||||
export type ParseErrorFunction = (err: string | DetailedError | unknown, hash?: any) => void;
|
||||
|
||||
export class Diagram {
|
||||
type = 'graph';
|
||||
@ -43,7 +44,7 @@ export class Diagram {
|
||||
this.parser.parser.yy = this.db;
|
||||
if (diagram.init) {
|
||||
diagram.init(cnf);
|
||||
log.debug('Initialized diagram ' + this.type, cnf);
|
||||
log.info('Initialized diagram ' + this.type, cnf);
|
||||
}
|
||||
this.txt += '\n';
|
||||
|
||||
|
@ -6,6 +6,13 @@ describe('accessibility', () => {
|
||||
const fauxSvgNode = new MockedD3();
|
||||
|
||||
describe('setA11yDiagramInfo', () => {
|
||||
it('sets the svg element role to "graphics-document document"', () => {
|
||||
// @ts-ignore Required to easily handle the d3 select types
|
||||
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
||||
setA11yDiagramInfo(fauxSvgNode, 'flowchart');
|
||||
expect(svgAttrSpy).toHaveBeenCalledWith('role', 'graphics-document document');
|
||||
});
|
||||
|
||||
it('sets the aria-roledescription to the diagram type', () => {
|
||||
// @ts-ignore Required to easily handle the d3 select types
|
||||
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
||||
@ -13,11 +20,12 @@ describe('accessibility', () => {
|
||||
expect(svgAttrSpy).toHaveBeenCalledWith('aria-roledescription', 'flowchart');
|
||||
});
|
||||
|
||||
it('does nothing if the diagram type is empty', () => {
|
||||
it('does not set the aria-roledescription if the diagram type is empty', () => {
|
||||
// @ts-ignore Required to easily handle the d3 select types
|
||||
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
||||
setA11yDiagramInfo(fauxSvgNode, '');
|
||||
expect(svgAttrSpy).not.toHaveBeenCalled();
|
||||
expect(svgAttrSpy).toHaveBeenCalledTimes(1);
|
||||
expect(svgAttrSpy).toHaveBeenCalledWith('role', expect.anything()); // only called to set the role
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
/**
|
||||
* Accessibility (a11y) functions, types, helpers
|
||||
* @see https://www.w3.org/WAI/
|
||||
* @see https://www.w3.org/TR/wai-aria-1.1/
|
||||
* @see https://www.w3.org/TR/svg-aam-1.0/
|
||||
*
|
||||
*/
|
||||
import { D3Element } from './mermaidAPI';
|
||||
@ -7,12 +10,24 @@ import { D3Element } from './mermaidAPI';
|
||||
import isEmpty from 'lodash-es/isEmpty.js';
|
||||
|
||||
/**
|
||||
* Add aria-roledescription to the svg element to the diagramType
|
||||
* SVG element role:
|
||||
* The SVG element role _should_ be set to 'graphics-document' per SVG standard
|
||||
* but in practice is not always done by browsers, etc. (As of 2022-12-08).
|
||||
* A fallback role of 'document' should be set for those browsers, etc., that only support ARIA 1.0.
|
||||
*
|
||||
* @see https://www.w3.org/TR/svg-aam-1.0/#roleMappingGeneralRules
|
||||
* @see https://www.w3.org/TR/graphics-aria-1.0/#graphics-document
|
||||
*/
|
||||
const SVG_ROLE = 'graphics-document document';
|
||||
|
||||
/**
|
||||
* Add role and aria-roledescription to the svg element
|
||||
*
|
||||
* @param svg - d3 object that contains the SVG HTML element
|
||||
* @param diagramType - diagram name for to the aria-roledescription
|
||||
*/
|
||||
export function setA11yDiagramInfo(svg: D3Element, diagramType: string | null | undefined) {
|
||||
svg.attr('role', SVG_ROLE);
|
||||
if (!isEmpty(diagramType)) {
|
||||
svg.attr('aria-roledescription', diagramType);
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ export interface MermaidConfig {
|
||||
sequence?: SequenceDiagramConfig;
|
||||
gantt?: GanttDiagramConfig;
|
||||
journey?: JourneyDiagramConfig;
|
||||
timeline?: TimelineDiagramConfig;
|
||||
class?: ClassDiagramConfig;
|
||||
state?: StateDiagramConfig;
|
||||
er?: ErDiagramConfig;
|
||||
@ -292,6 +293,30 @@ export interface JourneyDiagramConfig extends BaseDiagramConfig {
|
||||
sectionColours?: string[];
|
||||
}
|
||||
|
||||
export interface TimelineDiagramConfig extends BaseDiagramConfig {
|
||||
diagramMarginX?: number;
|
||||
diagramMarginY?: number;
|
||||
leftMargin?: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
boxMargin?: number;
|
||||
boxTextMargin?: number;
|
||||
noteMargin?: number;
|
||||
messageMargin?: number;
|
||||
messageAlign?: string;
|
||||
bottomMarginAdj?: number;
|
||||
rightAngles?: boolean;
|
||||
taskFontSize?: string | number;
|
||||
taskFontFamily?: string;
|
||||
taskMargin?: number;
|
||||
activationWidth?: number;
|
||||
textPlacement?: string;
|
||||
actorColours?: string[];
|
||||
sectionFills?: string[];
|
||||
sectionColours?: string[];
|
||||
disableMulticolor?: boolean;
|
||||
}
|
||||
|
||||
export interface GanttDiagramConfig extends BaseDiagramConfig {
|
||||
titleTopMargin?: number;
|
||||
barHeight?: number;
|
||||
|
@ -107,6 +107,7 @@ export const insertEdgeLabel = (elem, edge) => {
|
||||
terminalLabels[edge.id].endRight = endEdgeLabelRight;
|
||||
setTerminalWidth(fo, edge.endLabelRight);
|
||||
}
|
||||
return labelElement;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -142,7 +142,7 @@ const point = (elem, type) => {
|
||||
.append('marker')
|
||||
.attr('id', type + '-pointEnd')
|
||||
.attr('class', 'marker ' + type)
|
||||
.attr('viewBox', '0 0 10 10')
|
||||
.attr('viewBox', '0 0 12 20')
|
||||
.attr('refX', 10)
|
||||
.attr('refY', 5)
|
||||
.attr('markerUnits', 'userSpaceOnUse')
|
||||
|
@ -1007,6 +1007,7 @@ const class_box = (parent, node) => {
|
||||
};
|
||||
|
||||
const shapes = {
|
||||
rhombus: question,
|
||||
question,
|
||||
rect,
|
||||
labelRect,
|
||||
@ -1064,6 +1065,7 @@ export const insertNode = (elem, node, dir) => {
|
||||
if (node.haveCallback) {
|
||||
nodeElems[node.id].attr('class', nodeElems[node.id].attr('class') + ' clickable');
|
||||
}
|
||||
return newEl;
|
||||
};
|
||||
export const setNodeElem = (elem, node) => {
|
||||
nodeElems[node.id] = elem;
|
||||
|
@ -247,12 +247,13 @@ const config: Partial<MermaidConfig> = {
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | --------------- | ----------- | ------- | -------- | ----------------------- |
|
||||
* | defaultRenderer | See notes | boolean | 4 | dagre-d3, dagre-wrapper |
|
||||
* | defaultRenderer | See notes | boolean | 4 | dagre-d3, dagre-wrapper, elk |
|
||||
*
|
||||
* **Notes:**
|
||||
*
|
||||
* Decides which rendering engine that is to be used for the rendering. Legal values are:
|
||||
* dagre-d3 dagre-wrapper - wrapper for dagre implemented in mermaid
|
||||
* dagre-d3 dagre-wrapper - wrapper for dagre implemented in mermaid, elk for layout using
|
||||
* elkjs
|
||||
*
|
||||
* Default value: 'dagre-wrapper'
|
||||
*/
|
||||
@ -861,6 +862,156 @@ const config: Partial<MermaidConfig> = {
|
||||
sectionFills: ['#191970', '#8B008B', '#4B0082', '#2F4F4F', '#800000', '#8B4513', '#00008B'],
|
||||
sectionColours: ['#fff'],
|
||||
},
|
||||
/** The object containing configurations specific for timeline diagrams */
|
||||
timeline: {
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | -------------- | ---------------------------------------------------- | ------- | -------- | ------------------ |
|
||||
* | diagramMarginX | Margin to the right and left of the sequence diagram | Integer | Required | Any Positive Value |
|
||||
*
|
||||
* **Notes:** Default value: 50
|
||||
*/
|
||||
diagramMarginX: 50,
|
||||
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | -------------- | -------------------------------------------------- | ------- | -------- | ------------------ |
|
||||
* | diagramMarginY | Margin to the over and under the sequence diagram. | Integer | Required | Any Positive Value |
|
||||
*
|
||||
* **Notes:** Default value: 10
|
||||
*/
|
||||
diagramMarginY: 10,
|
||||
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | ----------- | --------------------- | ------- | -------- | ------------------ |
|
||||
* | actorMargin | Margin between actors | Integer | Required | Any Positive Value |
|
||||
*
|
||||
* **Notes:** Default value: 50
|
||||
*/
|
||||
leftMargin: 150,
|
||||
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | --------- | -------------------- | ------- | -------- | ------------------ |
|
||||
* | width | Width of actor boxes | Integer | Required | Any Positive Value |
|
||||
*
|
||||
* **Notes:** Default value: 150
|
||||
*/
|
||||
width: 150,
|
||||
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | --------- | --------------------- | ------- | -------- | ------------------ |
|
||||
* | height | Height of actor boxes | Integer | Required | Any Positive Value |
|
||||
*
|
||||
* **Notes:** Default value: 65
|
||||
*/
|
||||
height: 50,
|
||||
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | --------- | ------------------------ | ------- | -------- | ------------------ |
|
||||
* | boxMargin | Margin around loop boxes | Integer | Required | Any Positive Value |
|
||||
*
|
||||
* **Notes:** Default value: 10
|
||||
*/
|
||||
boxMargin: 10,
|
||||
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | ------------- | -------------------------------------------- | ------- | -------- | ------------------ |
|
||||
* | boxTextMargin | Margin around the text in loop/alt/opt boxes | Integer | Required | Any Positive Value |
|
||||
*
|
||||
* **Notes:** Default value: 5
|
||||
*/
|
||||
boxTextMargin: 5,
|
||||
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | ---------- | ------------------- | ------- | -------- | ------------------ |
|
||||
* | noteMargin | Margin around notes | Integer | Required | Any Positive Value |
|
||||
*
|
||||
* **Notes:** Default value: 10
|
||||
*/
|
||||
noteMargin: 10,
|
||||
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | ------------- | ----------------------- | ------- | -------- | ------------------ |
|
||||
* | messageMargin | Space between messages. | Integer | Required | Any Positive Value |
|
||||
*
|
||||
* **Notes:**
|
||||
*
|
||||
* Space between messages.
|
||||
*
|
||||
* Default value: 35
|
||||
*/
|
||||
messageMargin: 35,
|
||||
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | ------------ | --------------------------- | ---- | -------- | ------------------------- |
|
||||
* | messageAlign | Multiline message alignment | 3 | 4 | 'left', 'center', 'right' |
|
||||
*
|
||||
* **Notes:** Default value: 'center'
|
||||
*/
|
||||
messageAlign: 'center',
|
||||
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | --------------- | ------------------------------------------ | ------- | -------- | ------------------ |
|
||||
* | bottomMarginAdj | Prolongs the edge of the diagram downwards | Integer | 4 | Any Positive Value |
|
||||
*
|
||||
* **Notes:**
|
||||
*
|
||||
* Depending on css styling this might need adjustment.
|
||||
*
|
||||
* Default value: 1
|
||||
*/
|
||||
bottomMarginAdj: 1,
|
||||
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | ----------- | ----------- | ------- | -------- | ----------- |
|
||||
* | useMaxWidth | See notes | boolean | 4 | true, false |
|
||||
*
|
||||
* **Notes:**
|
||||
*
|
||||
* When this flag is set the height and width is set to 100% and is then scaling with the
|
||||
* available space if not the absolute space required is used.
|
||||
*
|
||||
* Default value: true
|
||||
*/
|
||||
useMaxWidth: true,
|
||||
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | ----------- | --------------------------------- | ---- | -------- | ----------- |
|
||||
* | rightAngles | Curved Arrows become Right Angles | 3 | 4 | true, false |
|
||||
*
|
||||
* **Notes:**
|
||||
*
|
||||
* This will display arrows that start and begin at the same node as right angles, rather than a
|
||||
* curves
|
||||
*
|
||||
* Default value: false
|
||||
*/
|
||||
rightAngles: false,
|
||||
taskFontSize: 14,
|
||||
taskFontFamily: '"Open Sans", sans-serif',
|
||||
taskMargin: 50,
|
||||
// width of activation box
|
||||
activationWidth: 10,
|
||||
|
||||
// text placement as: tspan | fo | old only text as before
|
||||
textPlacement: 'fo',
|
||||
actorColours: ['#8FBC8F', '#7CFC00', '#00FFFF', '#20B2AA', '#B0E0E6', '#FFFFE0'],
|
||||
|
||||
sectionFills: ['#191970', '#8B008B', '#4B0082', '#2F4F4F', '#800000', '#8B4513', '#00008B'],
|
||||
sectionColours: ['#fff'],
|
||||
disableMulticolor: false,
|
||||
},
|
||||
class: {
|
||||
/**
|
||||
* ### titleTopMargin
|
||||
|
@ -1,6 +1,11 @@
|
||||
import { MermaidConfig } from '../config.type';
|
||||
import { log } from '../logger';
|
||||
import { DetectorRecord, DiagramDetector, DiagramLoader } from './types';
|
||||
import type {
|
||||
DetectorRecord,
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from './types';
|
||||
import { frontMatterRegex } from './frontmatter';
|
||||
|
||||
const directive = /%{2}{\s*(?:(\w+)\s*:|(\w+))\s*(?:(\w+)|((?:(?!}%{2}).|\r?\n)*))?\s*(?:}%{2})?/gi;
|
||||
@ -42,11 +47,18 @@ export const detectType = function (text: string, config?: MermaidConfig): strin
|
||||
throw new Error(`No diagram type detected for text: ${text}`);
|
||||
};
|
||||
|
||||
export const registerLazyLoadedDiagrams = (...diagrams: ExternalDiagramDefinition[]) => {
|
||||
for (const { id, detector, loader } of diagrams) {
|
||||
addDetector(id, detector, loader);
|
||||
}
|
||||
};
|
||||
|
||||
export const addDetector = (key: string, detector: DiagramDetector, loader?: DiagramLoader) => {
|
||||
if (detectors[key]) {
|
||||
throw new Error(`Detector with key ${key} already exists`);
|
||||
log.error(`Detector with key ${key} already exists`);
|
||||
} else {
|
||||
detectors[key] = { detector, loader };
|
||||
}
|
||||
detectors[key] = { detector, loader };
|
||||
log.debug(`Detector with key ${key} added${loader ? ' with loader' : ''}`);
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { registerDiagram } from './diagramAPI';
|
||||
|
||||
// @ts-ignore: TODO Fix ts errors
|
||||
import gitGraphParser from '../diagrams/git/parser/gitGraph';
|
||||
import { gitGraphDetector } from '../diagrams/git/gitGraphDetector';
|
||||
@ -94,6 +93,13 @@ import { setConfig } from '../config';
|
||||
import errorRenderer from '../diagrams/error/errorRenderer';
|
||||
import errorStyles from '../diagrams/error/styles';
|
||||
|
||||
import flowchartElk from '../diagrams/flowchart/elk/detector';
|
||||
import { registerLazyLoadedDiagrams } from './detectType';
|
||||
|
||||
// Lazy loaded diagrams
|
||||
import timelineDetector from '../diagrams/timeline/detector';
|
||||
import mindmapDetector from '../diagrams/mindmap/detector';
|
||||
|
||||
let hasLoadedDiagrams = false;
|
||||
export const addDiagrams = () => {
|
||||
if (hasLoadedDiagrams) {
|
||||
@ -102,6 +108,8 @@ export const addDiagrams = () => {
|
||||
// This is added here to avoid race-conditions.
|
||||
// We could optimize the loading logic somehow.
|
||||
hasLoadedDiagrams = true;
|
||||
registerLazyLoadedDiagrams(flowchartElk, timelineDetector, mindmapDetector);
|
||||
|
||||
registerDiagram(
|
||||
'error',
|
||||
// Special diagram with error messages but setup as a regular diagram
|
||||
@ -125,6 +133,33 @@ export const addDiagrams = () => {
|
||||
},
|
||||
(text) => text.toLowerCase().trim() === 'error'
|
||||
);
|
||||
registerDiagram(
|
||||
'---',
|
||||
// --- diagram type may appear if YAML front-matter is not parsed correctly
|
||||
{
|
||||
db: {
|
||||
clear: () => {
|
||||
// Quite ok, clear needs to be there for --- to work as a regular diagram
|
||||
},
|
||||
},
|
||||
styles: errorStyles, // should never be used
|
||||
renderer: errorRenderer, // should never be used
|
||||
parser: {
|
||||
parser: { yy: {} },
|
||||
parse: () => {
|
||||
throw new Error(
|
||||
'Diagrams beginning with --- are not valid. ' +
|
||||
'If you were trying to use a YAML front-matter, please ensure that ' +
|
||||
"you've correctly opened and closed the YAML front-matter with unindented `---` blocks"
|
||||
);
|
||||
},
|
||||
},
|
||||
init: () => null, // no op
|
||||
},
|
||||
(text) => {
|
||||
return text.toLowerCase().trimStart().startsWith('---');
|
||||
}
|
||||
);
|
||||
|
||||
registerDiagram(
|
||||
'c4',
|
||||
|
@ -5,6 +5,8 @@ import { sanitizeText as _sanitizeText } from '../diagrams/common/common';
|
||||
import { setupGraphViewbox as _setupGraphViewbox } from '../setupGraphViewbox';
|
||||
import { addStylesForDiagram } from '../styles';
|
||||
import { DiagramDefinition, DiagramDetector } from './types';
|
||||
import * as _commonDb from '../commonDb';
|
||||
import { parseDirective as _parseDirective } from '../directiveUtils';
|
||||
|
||||
/*
|
||||
Packaging and exposing resources for external diagrams so that they can import
|
||||
@ -16,6 +18,11 @@ export const setLogLevel = _setLogLevel;
|
||||
export const getConfig = _getConfig;
|
||||
export const sanitizeText = (text: string) => _sanitizeText(text, getConfig());
|
||||
export const setupGraphViewbox = _setupGraphViewbox;
|
||||
export const getCommonDb = () => {
|
||||
return _commonDb;
|
||||
};
|
||||
export const parseDirective = (p: any, statement: string, context: string, type: string) =>
|
||||
_parseDirective(p, statement, context, type);
|
||||
|
||||
const diagrams: Record<string, DiagramDefinition> = {};
|
||||
export interface Detectors {
|
||||
@ -46,7 +53,15 @@ export const registerDiagram = (
|
||||
addStylesForDiagram(id, diagram.styles);
|
||||
|
||||
if (diagram.injectUtils) {
|
||||
diagram.injectUtils(log, setLogLevel, getConfig, sanitizeText, setupGraphViewbox);
|
||||
diagram.injectUtils(
|
||||
log,
|
||||
setLogLevel,
|
||||
getConfig,
|
||||
sanitizeText,
|
||||
setupGraphViewbox,
|
||||
getCommonDb(),
|
||||
parseDirective
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -6,6 +6,8 @@ export interface InjectUtils {
|
||||
_getConfig: any;
|
||||
_sanitizeText: any;
|
||||
_setupGraphViewbox: any;
|
||||
_commonDb: any;
|
||||
_parseDirective: any;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -29,7 +31,9 @@ export interface DiagramDefinition {
|
||||
_setLogLevel: InjectUtils['_setLogLevel'],
|
||||
_getConfig: InjectUtils['_getConfig'],
|
||||
_sanitizeText: InjectUtils['_sanitizeText'],
|
||||
_setupGraphViewbox: InjectUtils['_setupGraphViewbox']
|
||||
_setupGraphViewbox: InjectUtils['_setupGraphViewbox'],
|
||||
_commonDb: InjectUtils['_commonDb'],
|
||||
_parseDirective: InjectUtils['_parseDirective']
|
||||
) => void;
|
||||
}
|
||||
|
||||
|
@ -234,7 +234,7 @@ export const drawC4Shape = function (elem, c4Shape, conf) {
|
||||
const c4ShapeElem = elem.append('g');
|
||||
c4ShapeElem.attr('class', 'person-man');
|
||||
|
||||
// <rect fill="#08427B" height="119.2188" rx="2.5" ry="2.5" style="stroke:#073B6F;stroke-width:0.5;" width="110" x="120" y="7"/>
|
||||
// <rect fill="#08427B" height="119.2188" rx="2.5" ry="2.5" stroke="#073B6F" stroke-width="0.5" width="110" x="120" y="7"/>
|
||||
// draw rect of c4Shape
|
||||
const rect = getNoteRect();
|
||||
switch (c4Shape.typeC4Shape.text) {
|
||||
@ -251,9 +251,10 @@ export const drawC4Shape = function (elem, c4Shape, conf) {
|
||||
rect.fill = fillColor;
|
||||
rect.width = c4Shape.width;
|
||||
rect.height = c4Shape.height;
|
||||
rect.style = 'stroke:' + strokeColor + ';stroke-width:0.5;';
|
||||
rect.stroke = strokeColor;
|
||||
rect.rx = 2.5;
|
||||
rect.ry = 2.5;
|
||||
rect.attrs = { 'stroke-width': 0.5 };
|
||||
drawRect(c4ShapeElem, rect);
|
||||
break;
|
||||
case 'system_db':
|
||||
@ -371,12 +372,12 @@ export const drawC4Shape = function (elem, c4Shape, conf) {
|
||||
textFontConf = conf[c4Shape.typeC4Shape.text + 'Font']();
|
||||
textFontConf.fontColor = fontColor;
|
||||
|
||||
if (c4Shape.thchn && c4Shape.thchn.text !== '') {
|
||||
if (c4Shape.techn && c4Shape.techn?.text !== '') {
|
||||
_drawTextCandidateFunc(conf)(
|
||||
c4Shape.thchn.text,
|
||||
c4Shape.techn.text,
|
||||
c4ShapeElem,
|
||||
c4Shape.x,
|
||||
c4Shape.y + c4Shape.thchn.Y,
|
||||
c4Shape.y + c4Shape.techn.Y,
|
||||
c4Shape.width,
|
||||
c4Shape.height,
|
||||
{ fill: fontColor, 'font-style': 'italic' },
|
||||
|
@ -68,5 +68,7 @@ describe('generic parser', function () {
|
||||
expect(parseGenericTypes('test ~Array~Array~string[]~~~')).toEqual(
|
||||
'test <Array<Array<string[]>>>'
|
||||
);
|
||||
expect(parseGenericTypes('~test')).toEqual('~test');
|
||||
expect(parseGenericTypes('~test Array~string~')).toEqual('~test Array<string>');
|
||||
});
|
||||
});
|
||||
|
@ -154,11 +154,17 @@ export const evaluate = (val?: string | boolean): boolean =>
|
||||
export const parseGenericTypes = function (text: string): string {
|
||||
let cleanedText = text;
|
||||
|
||||
if (text.includes('~')) {
|
||||
cleanedText = cleanedText.replace(/~([^~].*)/, '<$1');
|
||||
cleanedText = cleanedText.replace(/~([^~]*)$/, '>$1');
|
||||
if (text.split('~').length - 1 >= 2) {
|
||||
let newCleanedText = cleanedText;
|
||||
|
||||
return parseGenericTypes(cleanedText);
|
||||
// use a do...while loop instead of replaceAll to detect recursion
|
||||
// e.g. Array~Array~T~~
|
||||
do {
|
||||
cleanedText = newCleanedText;
|
||||
newCleanedText = cleanedText.replace(/~([^\s,:;]+)~/, '<$1>');
|
||||
} while (newCleanedText != cleanedText);
|
||||
|
||||
return parseGenericTypes(newCleanedText);
|
||||
} else {
|
||||
return cleanedText;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import utils from '../../utils';
|
||||
import erMarkers from './erMarkers';
|
||||
import { configureSvgSize } from '../../setupGraphViewbox';
|
||||
import { parseGenericTypes } from '../common/common';
|
||||
import { v4 as uuid4 } from 'uuid';
|
||||
import { v5 as uuid5 } from 'uuid';
|
||||
|
||||
/** Regex used to remove chars from the entity name so the result can be used in an id */
|
||||
const BAD_ID_CHARS_REGEXP = /[^\dA-Za-z](\W)*/g;
|
||||
@ -59,7 +59,7 @@ const drawAttributes = (groupNode, entityTextNode, attributes) => {
|
||||
|
||||
// Check to see if any of the attributes has a key or a comment
|
||||
attributes.forEach((item) => {
|
||||
if (item.attributeKeyType !== undefined) {
|
||||
if (item.attributeKeyTypeList !== undefined && item.attributeKeyTypeList.length > 0) {
|
||||
hasKeyType = true;
|
||||
}
|
||||
|
||||
@ -112,6 +112,9 @@ const drawAttributes = (groupNode, entityTextNode, attributes) => {
|
||||
nodeHeight = Math.max(typeBBox.height, nameBBox.height);
|
||||
|
||||
if (hasKeyType) {
|
||||
const keyTypeNodeText =
|
||||
item.attributeKeyTypeList !== undefined ? item.attributeKeyTypeList.join(',') : '';
|
||||
|
||||
const keyTypeNode = groupNode
|
||||
.append('text')
|
||||
.classed('er entityLabel', true)
|
||||
@ -122,7 +125,7 @@ const drawAttributes = (groupNode, entityTextNode, attributes) => {
|
||||
.style('text-anchor', 'left')
|
||||
.style('font-family', getConfig().fontFamily)
|
||||
.style('font-size', attrFontSize + 'px')
|
||||
.text(item.attributeKeyType || '');
|
||||
.text(keyTypeNodeText);
|
||||
|
||||
attributeNode.kn = keyTypeNode;
|
||||
const keyTypeBBox = keyTypeNode.node().getBBox();
|
||||
@ -643,9 +646,24 @@ export const draw = function (text, id, _version, diagObj) {
|
||||
svg.attr('viewBox', `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`);
|
||||
}; // draw
|
||||
|
||||
/**
|
||||
* UUID namespace for ER diagram IDs
|
||||
*
|
||||
* This can be generated via running:
|
||||
*
|
||||
* ```js
|
||||
* const { v5: uuid5 } = await import('uuid');
|
||||
* uuid5(
|
||||
* 'https://mermaid-js.github.io/mermaid/syntax/entityRelationshipDiagram.html',
|
||||
* uuid5.URL
|
||||
* );
|
||||
* ```
|
||||
*/
|
||||
const MERMAID_ERDIAGRAM_UUID = '28e9f9db-3c8d-5aa5-9faf-44286ae5937c';
|
||||
|
||||
/**
|
||||
* Return a unique id based on the given string. Start with the prefix, then a hyphen, then the
|
||||
* simplified str, then a hyphen, then a unique uuid. (Hyphens are only included if needed.)
|
||||
* simplified str, then a hyphen, then a unique uuid based on the str. (Hyphens are only included if needed.)
|
||||
* Although the official XML standard for ids says that many more characters are valid in the id,
|
||||
* this keeps things simple by accepting only A-Za-z0-9.
|
||||
*
|
||||
@ -656,7 +674,11 @@ export const draw = function (text, id, _version, diagObj) {
|
||||
*/
|
||||
export function generateId(str = '', prefix = '') {
|
||||
const simplifiedStr = str.replace(BAD_ID_CHARS_REGEXP, '');
|
||||
return `${strWithHyphen(prefix)}${strWithHyphen(simplifiedStr)}${uuid4()}`;
|
||||
// we use `uuid v5` so that UUIDs are consistent given a string.
|
||||
return `${strWithHyphen(prefix)}${strWithHyphen(simplifiedStr)}${uuid5(
|
||||
str,
|
||||
MERMAID_ERDIAGRAM_UUID
|
||||
)}`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
12
packages/mermaid/src/diagrams/er/erRenderer.spec.ts
Normal file
12
packages/mermaid/src/diagrams/er/erRenderer.spec.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { generateId } from './erRenderer';
|
||||
|
||||
describe('erRenderer', () => {
|
||||
describe('generateId', () => {
|
||||
it('should be deterministic', () => {
|
||||
const id1 = generateId('hello world', 'my-prefix');
|
||||
const id2 = generateId('hello world', 'my-prefix');
|
||||
|
||||
expect(id1).toBe(id2);
|
||||
});
|
||||
});
|
||||
});
|
@ -28,10 +28,11 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
|
||||
\"[^"]*\" return 'WORD';
|
||||
"erDiagram" return 'ER_DIAGRAM';
|
||||
"{" { this.begin("block"); return 'BLOCK_START'; }
|
||||
<block>"," return 'COMMA';
|
||||
<block>\s+ /* skip whitespace in block */
|
||||
<block>\b((?:PK)|(?:FK))\b return 'ATTRIBUTE_KEY'
|
||||
<block>\b((?:PK)|(?:FK)|(?:UK))\b return 'ATTRIBUTE_KEY'
|
||||
<block>(.*?)[~](.*?)*[~] return 'ATTRIBUTE_WORD';
|
||||
<block>[A-Za-z][A-Za-z0-9\-_\[\]]* return 'ATTRIBUTE_WORD'
|
||||
<block>[A-Za-z_][A-Za-z0-9\-_\[\]\(\)]* return 'ATTRIBUTE_WORD'
|
||||
<block>\"[^"]*\" return 'COMMENT';
|
||||
<block>[\n]+ /* nothing */
|
||||
<block>"}" { this.popState(); return 'BLOCK_STOP'; }
|
||||
@ -80,7 +81,7 @@ start
|
||||
|
||||
document
|
||||
: /* empty */ { $$ = [] }
|
||||
| document line {$1.push($2);$$ = $1}
|
||||
| document line {$1.push($2);$$ = $1}
|
||||
;
|
||||
|
||||
line
|
||||
@ -131,11 +132,12 @@ attributes
|
||||
|
||||
attribute
|
||||
: attributeType attributeName { $$ = { attributeType: $1, attributeName: $2 }; }
|
||||
| attributeType attributeName attributeKeyType { $$ = { attributeType: $1, attributeName: $2, attributeKeyType: $3 }; }
|
||||
| attributeType attributeName attributeKeyTypeList { $$ = { attributeType: $1, attributeName: $2, attributeKeyTypeList: $3 }; }
|
||||
| attributeType attributeName attributeComment { $$ = { attributeType: $1, attributeName: $2, attributeComment: $3 }; }
|
||||
| attributeType attributeName attributeKeyType attributeComment { $$ = { attributeType: $1, attributeName: $2, attributeKeyType: $3, attributeComment: $4 }; }
|
||||
| attributeType attributeName attributeKeyTypeList attributeComment { $$ = { attributeType: $1, attributeName: $2, attributeKeyTypeList: $3, attributeComment: $4 }; }
|
||||
;
|
||||
|
||||
|
||||
attributeType
|
||||
: ATTRIBUTE_WORD { $$=$1; }
|
||||
;
|
||||
@ -144,6 +146,11 @@ attributeName
|
||||
: ATTRIBUTE_WORD { $$=$1; }
|
||||
;
|
||||
|
||||
attributeKeyTypeList
|
||||
: attributeKeyType { $$ = [$1]; }
|
||||
| attributeKeyTypeList COMMA attributeKeyType { $1.push($3); $$ = $1; }
|
||||
;
|
||||
|
||||
attributeKeyType
|
||||
: ATTRIBUTE_KEY { $$=$1; }
|
||||
;
|
||||
|
@ -135,6 +135,37 @@ describe('when parsing ER diagram it...', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('attribute name', () => {
|
||||
it('should allow alphanumeric characters, dashes, underscores and brackets (not leading chars)', function () {
|
||||
const entity = 'BOOK';
|
||||
const attribute1 = 'string myBookTitle';
|
||||
const attribute2 = 'string MYBOOKSUBTITLE_1';
|
||||
const attribute3 = 'string author-ref[name](1)';
|
||||
|
||||
erDiagram.parser.parse(
|
||||
`erDiagram\n${entity} {\n${attribute1}\n${attribute2}\n${attribute3}\n}`
|
||||
);
|
||||
const entities = erDb.getEntities();
|
||||
|
||||
expect(Object.keys(entities).length).toBe(1);
|
||||
expect(entities[entity].attributes.length).toBe(3);
|
||||
expect(entities[entity].attributes[0].attributeName).toBe('myBookTitle');
|
||||
expect(entities[entity].attributes[1].attributeName).toBe('MYBOOKSUBTITLE_1');
|
||||
expect(entities[entity].attributes[2].attributeName).toBe('author-ref[name](1)');
|
||||
});
|
||||
|
||||
it('should not allow leading numbers, dashes or brackets', function () {
|
||||
const entity = 'BOOK';
|
||||
const nonLeadingChars = '0-[]()';
|
||||
[...nonLeadingChars].forEach((nonLeadingChar) => {
|
||||
expect(() => {
|
||||
const attribute = `string ${nonLeadingChar}author`;
|
||||
erDiagram.parser.parse(`erDiagram\n${entity} {\n${attribute}\n}`);
|
||||
}).toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow an entity with a single attribute to be defined', function () {
|
||||
const entity = 'BOOK';
|
||||
const attribute = 'string title';
|
||||
@ -176,17 +207,40 @@ describe('when parsing ER diagram it...', function () {
|
||||
expect(entities[entity].attributes.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should allow an entity with attribute starting with fk or pk and a comment', function () {
|
||||
it('should allow an entity with attribute starting with fk, pk or uk and a comment', function () {
|
||||
const entity = 'BOOK';
|
||||
const attribute1 = 'int fk_title FK';
|
||||
const attribute2 = 'string pk_author PK';
|
||||
const attribute3 = 'float pk_price PK "comment"';
|
||||
const attribute3 = 'string uk_address UK';
|
||||
const attribute4 = 'float pk_price PK "comment"';
|
||||
|
||||
erDiagram.parser.parse(
|
||||
`erDiagram\n${entity} {\n${attribute1} \n\n${attribute2}\n${attribute3}\n}`
|
||||
`erDiagram\n${entity} {\n${attribute1} \n\n${attribute2}\n${attribute3}\n${attribute4}\n}`
|
||||
);
|
||||
const entities = erDb.getEntities();
|
||||
expect(entities[entity].attributes.length).toBe(3);
|
||||
expect(entities[entity].attributes.length).toBe(4);
|
||||
});
|
||||
|
||||
it('should allow an entity with attributes that have many constraints and comments', function () {
|
||||
const entity = 'CUSTOMER';
|
||||
const attribute1 = 'int customer_number PK, FK "comment1"';
|
||||
const attribute2 = 'datetime customer_status_start_datetime PK,UK, FK';
|
||||
const attribute3 = 'datetime customer_status_end_datetime PK , UK "comment3"';
|
||||
const attribute4 = 'string customer_firstname';
|
||||
const attribute5 = 'string customer_lastname "comment5"';
|
||||
|
||||
erDiagram.parser.parse(
|
||||
`erDiagram\n${entity} {\n${attribute1}\n${attribute2}\n${attribute3}\n${attribute4}\n${attribute5}\n}`
|
||||
);
|
||||
const entities = erDb.getEntities();
|
||||
expect(entities[entity].attributes[0].attributeKeyTypeList).toEqual(['PK', 'FK']);
|
||||
expect(entities[entity].attributes[0].attributeComment).toBe('comment1');
|
||||
expect(entities[entity].attributes[1].attributeKeyTypeList).toEqual(['PK', 'UK', 'FK']);
|
||||
expect(entities[entity].attributes[2].attributeKeyTypeList).toEqual(['PK', 'UK']);
|
||||
expect(entities[entity].attributes[2].attributeComment).toBe('comment3');
|
||||
expect(entities[entity].attributes[3].attributeKeyTypeList).toBeUndefined();
|
||||
expect(entities[entity].attributes[4].attributeKeyTypeList).toBeUndefined();
|
||||
expect(entities[entity].attributes[4].attributeComment).toBe('comment5');
|
||||
});
|
||||
|
||||
it('should allow an entity with attribute that has a generic type', function () {
|
||||
@ -214,6 +268,19 @@ describe('when parsing ER diagram it...', function () {
|
||||
expect(entities[entity].attributes.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should allow an entity with attribute that is a limited length string', function () {
|
||||
const entity = 'BOOK';
|
||||
const attribute1 = 'character(10) isbn FK';
|
||||
const attribute2 = 'varchar(5) postal_code "Five digits"';
|
||||
|
||||
erDiagram.parser.parse(`erDiagram\n${entity} {\n${attribute1}\n${attribute2}\n}`);
|
||||
const entities = erDb.getEntities();
|
||||
expect(Object.keys(entities).length).toBe(1);
|
||||
expect(entities[entity].attributes.length).toBe(2);
|
||||
expect(entities[entity].attributes[0].attributeType).toBe('character(10)');
|
||||
expect(entities[entity].attributes[1].attributeType).toBe('varchar(5)');
|
||||
});
|
||||
|
||||
it('should allow an entity with multiple attributes to be defined', function () {
|
||||
const entity = 'BOOK';
|
||||
const attribute1 = 'string title';
|
||||
|
55
packages/mermaid/src/diagrams/flowchart/elk/detector.spec.ts
Normal file
55
packages/mermaid/src/diagrams/flowchart/elk/detector.spec.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import plugin from './detector';
|
||||
import { describe, it } from 'vitest';
|
||||
|
||||
const { detector } = plugin;
|
||||
|
||||
describe('flowchart-elk detector', () => {
|
||||
it('should fail for dagre-d3', () => {
|
||||
expect(
|
||||
detector('flowchart', {
|
||||
flowchart: {
|
||||
defaultRenderer: 'dagre-d3',
|
||||
},
|
||||
})
|
||||
).toBe(false);
|
||||
});
|
||||
it('should fail for dagre-wrapper', () => {
|
||||
expect(
|
||||
detector('flowchart', {
|
||||
flowchart: {
|
||||
defaultRenderer: 'dagre-wrapper',
|
||||
},
|
||||
})
|
||||
).toBe(false);
|
||||
});
|
||||
it('should succeed for elk', () => {
|
||||
expect(
|
||||
detector('flowchart', {
|
||||
flowchart: {
|
||||
defaultRenderer: 'elk',
|
||||
},
|
||||
})
|
||||
).toBe(true);
|
||||
expect(
|
||||
detector('graph', {
|
||||
flowchart: {
|
||||
defaultRenderer: 'elk',
|
||||
},
|
||||
})
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should detect flowchart-elk', () => {
|
||||
expect(detector('flowchart-elk')).toBe(true);
|
||||
});
|
||||
|
||||
it('should not detect class with defaultRenderer set to elk', () => {
|
||||
expect(
|
||||
detector('class', {
|
||||
flowchart: {
|
||||
defaultRenderer: 'elk',
|
||||
},
|
||||
})
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
29
packages/mermaid/src/diagrams/flowchart/elk/detector.ts
Normal file
29
packages/mermaid/src/diagrams/flowchart/elk/detector.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import type { MermaidConfig } from '../../../config.type';
|
||||
import type { ExternalDiagramDefinition, DiagramDetector } from '../../../diagram-api/types';
|
||||
|
||||
const id = 'flowchart-elk';
|
||||
|
||||
const detector: DiagramDetector = (txt: string, config?: MermaidConfig): boolean => {
|
||||
if (
|
||||
// If diagram explicitly states flowchart-elk
|
||||
txt.match(/^\s*flowchart-elk/) ||
|
||||
// If a flowchart/graph diagram has their default renderer set to elk
|
||||
(txt.match(/^\s*flowchart|graph/) && config?.flowchart?.defaultRenderer === 'elk')
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const { diagram } = await import('./diagram-definition');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
const plugin: ExternalDiagramDefinition = {
|
||||
id,
|
||||
detector,
|
||||
loader,
|
||||
};
|
||||
|
||||
export default plugin;
|
@ -0,0 +1,13 @@
|
||||
// @ts-ignore: JISON typing missing
|
||||
import parser from '../parser/flow';
|
||||
|
||||
import * as db from '../flowDb';
|
||||
import renderer from './flowRenderer-elk';
|
||||
import styles from './styles';
|
||||
|
||||
export const diagram = {
|
||||
db,
|
||||
renderer,
|
||||
parser,
|
||||
styles,
|
||||
};
|
953
packages/mermaid/src/diagrams/flowchart/elk/flowRenderer-elk.js
Normal file
953
packages/mermaid/src/diagrams/flowchart/elk/flowRenderer-elk.js
Normal file
@ -0,0 +1,953 @@
|
||||
import { select, line, curveLinear } from 'd3';
|
||||
import { insertNode } from '../../../dagre-wrapper/nodes.js';
|
||||
import insertMarkers from '../../../dagre-wrapper/markers.js';
|
||||
import { insertEdgeLabel } from '../../../dagre-wrapper/edges.js';
|
||||
import { findCommonAncestor } from './render-utils';
|
||||
import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js';
|
||||
import { getConfig } from '../../../config';
|
||||
import { log } from '../../../logger';
|
||||
import { setupGraphViewbox } from '../../../setupGraphViewbox';
|
||||
import common, { evaluate } from '../../common/common';
|
||||
import { interpolateToCurve, getStylesFromArray } from '../../../utils';
|
||||
|
||||
import ELK from 'elkjs/lib/elk.bundled.js';
|
||||
const elk = new ELK();
|
||||
|
||||
const portPos = {};
|
||||
|
||||
const conf = {};
|
||||
export const setConf = function (cnf) {
|
||||
const keys = Object.keys(cnf);
|
||||
for (const key of keys) {
|
||||
conf[key] = cnf[key];
|
||||
}
|
||||
};
|
||||
|
||||
let nodeDb = {};
|
||||
|
||||
// /**
|
||||
// * Function that adds the vertices found during parsing to the graph to be rendered.
|
||||
// *
|
||||
// * @param vert Object containing the vertices.
|
||||
// * @param g The graph that is to be drawn.
|
||||
// * @param svgId
|
||||
// * @param root
|
||||
// * @param doc
|
||||
// * @param diagObj
|
||||
// */
|
||||
export const addVertices = function (vert, svgId, root, doc, diagObj, parentLookupDb, graph) {
|
||||
const svg = root.select(`[id="${svgId}"]`);
|
||||
const nodes = svg.insert('g').attr('class', 'nodes');
|
||||
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) {
|
||||
const vertex = vert[id];
|
||||
|
||||
/**
|
||||
* Variable for storing the classes for the vertex
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
let classStr = 'default';
|
||||
if (vertex.classes.length > 0) {
|
||||
classStr = vertex.classes.join(' ');
|
||||
}
|
||||
|
||||
const styles = getStylesFromArray(vertex.styles);
|
||||
|
||||
// Use vertex id as text in the box if no text is provided by the graph definition
|
||||
let vertexText = vertex.text !== undefined ? vertex.text : vertex.id;
|
||||
|
||||
// We create a SVG label, either by delegating to addHtmlLabel or manually
|
||||
let vertexNode;
|
||||
const labelData = { width: 0, height: 0 };
|
||||
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>`
|
||||
),
|
||||
};
|
||||
vertexNode = addHtmlLabel(svg, node).node();
|
||||
const bbox = vertexNode.getBBox();
|
||||
labelData.width = bbox.width;
|
||||
labelData.height = bbox.height;
|
||||
labelData.labelNode = vertexNode;
|
||||
vertexNode.parentNode.removeChild(vertexNode);
|
||||
} else {
|
||||
const svgLabel = doc.createElementNS('http://www.w3.org/2000/svg', 'text');
|
||||
svgLabel.setAttribute('style', styles.labelStyle.replace('color:', 'fill:'));
|
||||
|
||||
const rows = vertexText.split(common.lineBreakRegex);
|
||||
|
||||
for (const row of rows) {
|
||||
const tspan = doc.createElementNS('http://www.w3.org/2000/svg', 'tspan');
|
||||
tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
|
||||
tspan.setAttribute('dy', '1em');
|
||||
tspan.setAttribute('x', '1');
|
||||
tspan.textContent = row;
|
||||
svgLabel.appendChild(tspan);
|
||||
}
|
||||
vertexNode = svgLabel;
|
||||
const bbox = vertexNode.getBBox();
|
||||
labelData.width = bbox.width;
|
||||
labelData.height = bbox.height;
|
||||
labelData.labelNode = vertexNode;
|
||||
}
|
||||
|
||||
const ports = [
|
||||
{
|
||||
id: vertex.id + '-west',
|
||||
layoutOptions: {
|
||||
'port.side': 'WEST',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: vertex.id + '-east',
|
||||
layoutOptions: {
|
||||
'port.side': 'EAST',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: vertex.id + '-south',
|
||||
layoutOptions: {
|
||||
'port.side': 'SOUTH',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: vertex.id + '-north',
|
||||
layoutOptions: {
|
||||
'port.side': 'NORTH',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
let radious = 0;
|
||||
let _shape = '';
|
||||
let layoutOptions = {};
|
||||
// Set the shape based parameters
|
||||
switch (vertex.type) {
|
||||
case 'round':
|
||||
radious = 5;
|
||||
_shape = 'rect';
|
||||
break;
|
||||
case 'square':
|
||||
_shape = 'rect';
|
||||
break;
|
||||
case 'diamond':
|
||||
_shape = 'question';
|
||||
layoutOptions = {
|
||||
portConstraints: 'FIXED_SIDE',
|
||||
};
|
||||
break;
|
||||
case 'hexagon':
|
||||
_shape = 'hexagon';
|
||||
break;
|
||||
case 'odd':
|
||||
_shape = 'rect_left_inv_arrow';
|
||||
break;
|
||||
case 'lean_right':
|
||||
_shape = 'lean_right';
|
||||
break;
|
||||
case 'lean_left':
|
||||
_shape = 'lean_left';
|
||||
break;
|
||||
case 'trapezoid':
|
||||
_shape = 'trapezoid';
|
||||
break;
|
||||
case 'inv_trapezoid':
|
||||
_shape = 'inv_trapezoid';
|
||||
break;
|
||||
case 'odd_right':
|
||||
_shape = 'rect_left_inv_arrow';
|
||||
break;
|
||||
case 'circle':
|
||||
_shape = 'circle';
|
||||
break;
|
||||
case 'ellipse':
|
||||
_shape = 'ellipse';
|
||||
break;
|
||||
case 'stadium':
|
||||
_shape = 'stadium';
|
||||
break;
|
||||
case 'subroutine':
|
||||
_shape = 'subroutine';
|
||||
break;
|
||||
case 'cylinder':
|
||||
_shape = 'cylinder';
|
||||
break;
|
||||
case 'group':
|
||||
_shape = 'rect';
|
||||
break;
|
||||
case 'doublecircle':
|
||||
_shape = 'doublecircle';
|
||||
break;
|
||||
default:
|
||||
_shape = 'rect';
|
||||
}
|
||||
// // Add the node
|
||||
const node = {
|
||||
labelStyle: styles.labelStyle,
|
||||
shape: _shape,
|
||||
labelText: vertexText,
|
||||
rx: radious,
|
||||
ry: radious,
|
||||
class: classStr,
|
||||
style: styles.style,
|
||||
id: vertex.id,
|
||||
link: vertex.link,
|
||||
linkTarget: vertex.linkTarget,
|
||||
tooltip: diagObj.db.getTooltip(vertex.id) || '',
|
||||
domId: diagObj.db.lookUpDomId(vertex.id),
|
||||
haveCallback: vertex.haveCallback,
|
||||
width: vertex.type === 'group' ? 500 : undefined,
|
||||
dir: vertex.dir,
|
||||
type: vertex.type,
|
||||
props: vertex.props,
|
||||
padding: getConfig().flowchart.padding,
|
||||
};
|
||||
let boundingBox;
|
||||
let nodeEl;
|
||||
if (node.type !== 'group') {
|
||||
nodeEl = insertNode(nodes, node, vertex.dir);
|
||||
boundingBox = nodeEl.node().getBBox();
|
||||
}
|
||||
|
||||
const data = {
|
||||
id: vertex.id,
|
||||
ports: vertex.type === 'diamond' ? ports : [],
|
||||
// labelStyle: styles.labelStyle,
|
||||
// shape: _shape,
|
||||
layoutOptions,
|
||||
labelText: vertexText,
|
||||
labelData,
|
||||
// labels: [{ text: vertexText }],
|
||||
// rx: radius,
|
||||
// ry: radius,
|
||||
// class: classStr,
|
||||
// style: styles.style,
|
||||
// link: vertex.link,
|
||||
// linkTarget: vertex.linkTarget,
|
||||
// tooltip: diagObj.db.getTooltip(vertex.id) || '',
|
||||
domId: diagObj.db.lookUpDomId(vertex.id),
|
||||
// haveCallback: vertex.haveCallback,
|
||||
width: boundingBox?.width,
|
||||
height: boundingBox?.height,
|
||||
// dir: vertex.dir,
|
||||
type: vertex.type,
|
||||
// props: vertex.props,
|
||||
// padding: getConfig().flowchart.padding,
|
||||
// boundingBox,
|
||||
el: nodeEl,
|
||||
parent: parentLookupDb.parentById[vertex.id],
|
||||
};
|
||||
// if (!Object.keys(parentLookupDb.childrenById).includes(vertex.id)) {
|
||||
// graph.children.push({
|
||||
// ...data,
|
||||
// });
|
||||
// }
|
||||
nodeDb[node.id] = data;
|
||||
// log.trace('setNode', {
|
||||
// labelStyle: styles.labelStyle,
|
||||
// shape: _shape,
|
||||
// labelText: vertexText,
|
||||
// rx: radius,
|
||||
// ry: radius,
|
||||
// class: classStr,
|
||||
// style: styles.style,
|
||||
// id: vertex.id,
|
||||
// domId: diagObj.db.lookUpDomId(vertex.id),
|
||||
// width: vertex.type === 'group' ? 500 : undefined,
|
||||
// type: vertex.type,
|
||||
// dir: vertex.dir,
|
||||
// props: vertex.props,
|
||||
// padding: getConfig().flowchart.padding,
|
||||
// parent: parentLookupDb.parentById[vertex.id],
|
||||
// });
|
||||
});
|
||||
return graph;
|
||||
};
|
||||
|
||||
const getNextPosition = (position, edgeDirection, graphDirection) => {
|
||||
const portPos = {
|
||||
TB: {
|
||||
in: {
|
||||
north: 'north',
|
||||
},
|
||||
out: {
|
||||
south: 'west',
|
||||
west: 'east',
|
||||
east: 'south',
|
||||
},
|
||||
},
|
||||
LR: {
|
||||
in: {
|
||||
west: 'west',
|
||||
},
|
||||
out: {
|
||||
east: 'south',
|
||||
south: 'north',
|
||||
north: 'east',
|
||||
},
|
||||
},
|
||||
RL: {
|
||||
in: {
|
||||
east: 'east',
|
||||
},
|
||||
out: {
|
||||
west: 'north',
|
||||
north: 'south',
|
||||
south: 'west',
|
||||
},
|
||||
},
|
||||
BT: {
|
||||
in: {
|
||||
south: 'south',
|
||||
},
|
||||
out: {
|
||||
north: 'east',
|
||||
east: 'west',
|
||||
west: 'north',
|
||||
},
|
||||
},
|
||||
};
|
||||
portPos.TD = portPos.TB;
|
||||
log.info('abc88', graphDirection, edgeDirection, position);
|
||||
return portPos[graphDirection][edgeDirection][position];
|
||||
// return 'south';
|
||||
};
|
||||
|
||||
const getNextPort = (node, edgeDirection, graphDirection) => {
|
||||
log.info('getNextPort abc88', { node, edgeDirection, graphDirection });
|
||||
if (!portPos[node]) {
|
||||
switch (graphDirection) {
|
||||
case 'TB':
|
||||
case 'TD':
|
||||
portPos[node] = {
|
||||
inPosition: 'north',
|
||||
outPosition: 'south',
|
||||
};
|
||||
break;
|
||||
case 'BT':
|
||||
portPos[node] = {
|
||||
inPosition: 'south',
|
||||
outPosition: 'north',
|
||||
};
|
||||
break;
|
||||
case 'RL':
|
||||
portPos[node] = {
|
||||
inPosition: 'east',
|
||||
outPosition: 'west',
|
||||
};
|
||||
break;
|
||||
case 'LR':
|
||||
portPos[node] = {
|
||||
inPosition: 'west',
|
||||
outPosition: 'east',
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
const result = edgeDirection === 'in' ? portPos[node].inPosition : portPos[node].outPosition;
|
||||
|
||||
if (edgeDirection === 'in') {
|
||||
portPos[node].inPosition = getNextPosition(
|
||||
portPos[node].inPosition,
|
||||
edgeDirection,
|
||||
graphDirection
|
||||
);
|
||||
} else {
|
||||
portPos[node].outPosition = getNextPosition(
|
||||
portPos[node].outPosition,
|
||||
edgeDirection,
|
||||
graphDirection
|
||||
);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
const getEdgeStartEndPoint = (edge, dir) => {
|
||||
let source = edge.start;
|
||||
let target = edge.end;
|
||||
|
||||
const startNode = nodeDb[source];
|
||||
const endNode = nodeDb[target];
|
||||
|
||||
if (!startNode || !endNode) {
|
||||
return { source, target };
|
||||
}
|
||||
|
||||
if (startNode.type === 'diamond') {
|
||||
source = `${source}-${getNextPort(source, 'out', dir)}`;
|
||||
}
|
||||
|
||||
if (endNode.type === 'diamond') {
|
||||
target = `${target}-${getNextPort(target, 'in', dir)}`;
|
||||
}
|
||||
|
||||
// Add the edge to the graph
|
||||
return { source, target };
|
||||
};
|
||||
|
||||
/**
|
||||
* Add edges to graph based on parsed graph definition
|
||||
*
|
||||
* @param {object} edges The edges to add to the graph
|
||||
* @param {object} g The graph object
|
||||
* @param cy
|
||||
* @param diagObj
|
||||
* @param graph
|
||||
* @param svg
|
||||
*/
|
||||
export const addEdges = function (edges, diagObj, graph, svg) {
|
||||
log.info('abc78 edges = ', edges);
|
||||
const labelsEl = svg.insert('g').attr('class', 'edgeLabels');
|
||||
let linkIdCnt = {};
|
||||
let dir = diagObj.db.getDirection();
|
||||
let defaultStyle;
|
||||
let defaultLabelStyle;
|
||||
|
||||
if (edges.defaultStyle !== undefined) {
|
||||
const defaultStyles = getStylesFromArray(edges.defaultStyle);
|
||||
defaultStyle = defaultStyles.style;
|
||||
defaultLabelStyle = defaultStyles.labelStyle;
|
||||
}
|
||||
|
||||
edges.forEach(function (edge) {
|
||||
// Identify Link
|
||||
var linkIdBase = 'L-' + edge.start + '-' + edge.end;
|
||||
// count the links from+to the same node to give unique id
|
||||
if (linkIdCnt[linkIdBase] === undefined) {
|
||||
linkIdCnt[linkIdBase] = 0;
|
||||
log.info('abc78 new entry', linkIdBase, linkIdCnt[linkIdBase]);
|
||||
} else {
|
||||
linkIdCnt[linkIdBase]++;
|
||||
log.info('abc78 new entry', linkIdBase, linkIdCnt[linkIdBase]);
|
||||
}
|
||||
let linkId = linkIdBase + '-' + linkIdCnt[linkIdBase];
|
||||
log.info('abc78 new link id to be used is', linkIdBase, linkId, linkIdCnt[linkIdBase]);
|
||||
var linkNameStart = 'LS-' + edge.start;
|
||||
var linkNameEnd = 'LE-' + edge.end;
|
||||
|
||||
const edgeData = { style: '', labelStyle: '' };
|
||||
edgeData.minlen = edge.length || 1;
|
||||
//edgeData.id = 'id' + cnt;
|
||||
|
||||
// Set link type for rendering
|
||||
if (edge.type === 'arrow_open') {
|
||||
edgeData.arrowhead = 'none';
|
||||
} else {
|
||||
edgeData.arrowhead = 'normal';
|
||||
}
|
||||
|
||||
// Check of arrow types, placed here in order not to break old rendering
|
||||
edgeData.arrowTypeStart = 'arrow_open';
|
||||
edgeData.arrowTypeEnd = 'arrow_open';
|
||||
|
||||
/* eslint-disable no-fallthrough */
|
||||
switch (edge.type) {
|
||||
case 'double_arrow_cross':
|
||||
edgeData.arrowTypeStart = 'arrow_cross';
|
||||
case 'arrow_cross':
|
||||
edgeData.arrowTypeEnd = 'arrow_cross';
|
||||
break;
|
||||
case 'double_arrow_point':
|
||||
edgeData.arrowTypeStart = 'arrow_point';
|
||||
case 'arrow_point':
|
||||
edgeData.arrowTypeEnd = 'arrow_point';
|
||||
break;
|
||||
case 'double_arrow_circle':
|
||||
edgeData.arrowTypeStart = 'arrow_circle';
|
||||
case 'arrow_circle':
|
||||
edgeData.arrowTypeEnd = 'arrow_circle';
|
||||
break;
|
||||
}
|
||||
|
||||
let style = '';
|
||||
let labelStyle = '';
|
||||
|
||||
switch (edge.stroke) {
|
||||
case 'normal':
|
||||
style = 'fill:none;';
|
||||
if (defaultStyle !== undefined) {
|
||||
style = defaultStyle;
|
||||
}
|
||||
if (defaultLabelStyle !== undefined) {
|
||||
labelStyle = defaultLabelStyle;
|
||||
}
|
||||
edgeData.thickness = 'normal';
|
||||
edgeData.pattern = 'solid';
|
||||
break;
|
||||
case 'dotted':
|
||||
edgeData.thickness = 'normal';
|
||||
edgeData.pattern = 'dotted';
|
||||
edgeData.style = 'fill:none;stroke-width:2px;stroke-dasharray:3;';
|
||||
break;
|
||||
case 'thick':
|
||||
edgeData.thickness = 'thick';
|
||||
edgeData.pattern = 'solid';
|
||||
edgeData.style = 'stroke-width: 3.5px;fill:none;';
|
||||
break;
|
||||
}
|
||||
if (edge.style !== undefined) {
|
||||
const styles = getStylesFromArray(edge.style);
|
||||
style = styles.style;
|
||||
labelStyle = styles.labelStyle;
|
||||
}
|
||||
|
||||
edgeData.style = edgeData.style += style;
|
||||
edgeData.labelStyle = edgeData.labelStyle += labelStyle;
|
||||
|
||||
if (edge.interpolate !== undefined) {
|
||||
edgeData.curve = interpolateToCurve(edge.interpolate, curveLinear);
|
||||
} else if (edges.defaultInterpolate !== undefined) {
|
||||
edgeData.curve = interpolateToCurve(edges.defaultInterpolate, curveLinear);
|
||||
} else {
|
||||
edgeData.curve = interpolateToCurve(conf.curve, curveLinear);
|
||||
}
|
||||
|
||||
if (edge.text === undefined) {
|
||||
if (edge.style !== undefined) {
|
||||
edgeData.arrowheadStyle = 'fill: #333';
|
||||
}
|
||||
} else {
|
||||
edgeData.arrowheadStyle = 'fill: #333';
|
||||
edgeData.labelpos = 'c';
|
||||
}
|
||||
|
||||
edgeData.labelType = 'text';
|
||||
edgeData.label = edge.text.replace(common.lineBreakRegex, '\n');
|
||||
|
||||
if (edge.style === undefined) {
|
||||
edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none;';
|
||||
}
|
||||
|
||||
edgeData.labelStyle = edgeData.labelStyle.replace('color:', 'fill:');
|
||||
|
||||
edgeData.id = linkId;
|
||||
edgeData.classes = 'flowchart-link ' + linkNameStart + ' ' + linkNameEnd;
|
||||
|
||||
const labelEl = insertEdgeLabel(labelsEl, edgeData);
|
||||
|
||||
// calculate start and end points of the edge
|
||||
const { source, target } = getEdgeStartEndPoint(edge, dir);
|
||||
log.debug('abc78 source and target', source, target);
|
||||
// Add the edge to the graph
|
||||
graph.edges.push({
|
||||
id: 'e' + edge.start + edge.end,
|
||||
sources: [source],
|
||||
targets: [target],
|
||||
labelEl: labelEl,
|
||||
labels: [
|
||||
{
|
||||
width: edgeData.width,
|
||||
height: edgeData.height,
|
||||
orgWidth: edgeData.width,
|
||||
orgHeight: edgeData.height,
|
||||
text: edgeData.label,
|
||||
layoutOptions: {
|
||||
'edgeLabels.inline': 'true',
|
||||
'edgeLabels.placement': 'CENTER',
|
||||
},
|
||||
},
|
||||
],
|
||||
edgeData,
|
||||
});
|
||||
});
|
||||
return graph;
|
||||
};
|
||||
|
||||
// TODO: break out and share with dagre wrapper. The current code in dagre wrapper also adds
|
||||
// adds the line to the graph, but we don't need that here. This is why we cant use the dagre
|
||||
// wrapper directly for this
|
||||
/**
|
||||
* Add the markers to the edge depending on the type of arrow is
|
||||
* @param svgPath
|
||||
* @param edgeData
|
||||
* @param diagramType
|
||||
* @param arrowMarkerAbsolute
|
||||
*/
|
||||
const addMarkersToEdge = function (svgPath, edgeData, diagramType, arrowMarkerAbsolute) {
|
||||
let url = '';
|
||||
// Check configuration for absolute path
|
||||
if (arrowMarkerAbsolute) {
|
||||
url =
|
||||
window.location.protocol +
|
||||
'//' +
|
||||
window.location.host +
|
||||
window.location.pathname +
|
||||
window.location.search;
|
||||
url = url.replace(/\(/g, '\\(');
|
||||
url = url.replace(/\)/g, '\\)');
|
||||
}
|
||||
|
||||
// look in edge data and decide which marker to use
|
||||
switch (edgeData.arrowTypeStart) {
|
||||
case 'arrow_cross':
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-crossStart' + ')');
|
||||
break;
|
||||
case 'arrow_point':
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-pointStart' + ')');
|
||||
break;
|
||||
case 'arrow_barb':
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-barbStart' + ')');
|
||||
break;
|
||||
case 'arrow_circle':
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-circleStart' + ')');
|
||||
break;
|
||||
case 'aggregation':
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-aggregationStart' + ')');
|
||||
break;
|
||||
case 'extension':
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-extensionStart' + ')');
|
||||
break;
|
||||
case 'composition':
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-compositionStart' + ')');
|
||||
break;
|
||||
case 'dependency':
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-dependencyStart' + ')');
|
||||
break;
|
||||
case 'lollipop':
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-lollipopStart' + ')');
|
||||
break;
|
||||
default:
|
||||
}
|
||||
switch (edgeData.arrowTypeEnd) {
|
||||
case 'arrow_cross':
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-crossEnd' + ')');
|
||||
break;
|
||||
case 'arrow_point':
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-pointEnd' + ')');
|
||||
break;
|
||||
case 'arrow_barb':
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-barbEnd' + ')');
|
||||
break;
|
||||
case 'arrow_circle':
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-circleEnd' + ')');
|
||||
break;
|
||||
case 'aggregation':
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-aggregationEnd' + ')');
|
||||
break;
|
||||
case 'extension':
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-extensionEnd' + ')');
|
||||
break;
|
||||
case 'composition':
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-compositionEnd' + ')');
|
||||
break;
|
||||
case 'dependency':
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-dependencyEnd' + ')');
|
||||
break;
|
||||
case 'lollipop':
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-lollipopEnd' + ')');
|
||||
break;
|
||||
default:
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the all the styles from classDef statements in the graph definition.
|
||||
*
|
||||
* @param text
|
||||
* @param diagObj
|
||||
* @returns {object} ClassDef styles
|
||||
*/
|
||||
export const getClasses = function (text, diagObj) {
|
||||
log.info('Extracting classes');
|
||||
diagObj.db.clear('ver-2');
|
||||
try {
|
||||
// Parse the graph definition
|
||||
diagObj.parse(text);
|
||||
return diagObj.db.getClasses();
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
const addSubGraphs = function (db) {
|
||||
const parentLookupDb = { parentById: {}, childrenById: {} };
|
||||
const subgraphs = db.getSubGraphs();
|
||||
log.info('Subgraphs - ', subgraphs);
|
||||
subgraphs.forEach(function (subgraph) {
|
||||
subgraph.nodes.forEach(function (node) {
|
||||
parentLookupDb.parentById[node] = subgraph.id;
|
||||
if (parentLookupDb.childrenById[subgraph.id] === undefined) {
|
||||
parentLookupDb.childrenById[subgraph.id] = [];
|
||||
}
|
||||
parentLookupDb.childrenById[subgraph.id].push(node);
|
||||
});
|
||||
});
|
||||
|
||||
subgraphs.forEach(function (subgraph) {
|
||||
const data = { id: subgraph.id };
|
||||
if (parentLookupDb.parentById[subgraph.id] !== undefined) {
|
||||
data.parent = parentLookupDb.parentById[subgraph.id];
|
||||
}
|
||||
});
|
||||
return parentLookupDb;
|
||||
};
|
||||
|
||||
const calcOffset = function (src, dest, parentLookupDb) {
|
||||
const ancestor = findCommonAncestor(src, dest, parentLookupDb);
|
||||
if (ancestor === undefined || ancestor === 'root') {
|
||||
return { x: 0, y: 0 };
|
||||
}
|
||||
|
||||
const ancestorOffset = nodeDb[ancestor].offset;
|
||||
return { x: ancestorOffset.posX, y: ancestorOffset.posY };
|
||||
};
|
||||
|
||||
const insertEdge = function (edgesEl, edge, edgeData, diagObj, parentLookupDb) {
|
||||
const offset = calcOffset(edge.sources[0], edge.targets[0], parentLookupDb);
|
||||
|
||||
const src = edge.sections[0].startPoint;
|
||||
const dest = edge.sections[0].endPoint;
|
||||
const segments = edge.sections[0].bendPoints ? edge.sections[0].bendPoints : [];
|
||||
|
||||
const segPoints = segments.map((segment) => [segment.x + offset.x, segment.y + offset.y]);
|
||||
const points = [
|
||||
[src.x + offset.x, src.y + offset.y],
|
||||
...segPoints,
|
||||
[dest.x + offset.x, dest.y + offset.y],
|
||||
];
|
||||
|
||||
// const curve = line().curve(curveBasis);
|
||||
const curve = line().curve(curveLinear);
|
||||
const edgePath = edgesEl
|
||||
.insert('path')
|
||||
.attr('d', curve(points))
|
||||
.attr('class', 'path')
|
||||
.attr('fill', 'none');
|
||||
const edgeG = edgesEl.insert('g').attr('class', 'edgeLabel');
|
||||
const edgeWithLabel = select(edgeG.node().appendChild(edge.labelEl));
|
||||
const box = edgeWithLabel.node().firstChild.getBoundingClientRect();
|
||||
edgeWithLabel.attr('width', box.width);
|
||||
edgeWithLabel.attr('height', box.height);
|
||||
|
||||
edgeG.attr(
|
||||
'transform',
|
||||
`translate(${edge.labels[0].x + offset.x}, ${edge.labels[0].y + offset.y})`
|
||||
);
|
||||
addMarkersToEdge(edgePath, edgeData, diagObj.type, diagObj.arrowMarkerAbsolute);
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursive function that iterates over an array of nodes and inserts the children of each node.
|
||||
* It also recursively populates the inserts the children of the children and so on.
|
||||
* @param {*} graph
|
||||
* @param nodeArray
|
||||
* @param parentLookupDb
|
||||
*/
|
||||
const insertChildren = (nodeArray, parentLookupDb) => {
|
||||
nodeArray.forEach((node) => {
|
||||
// Check if we have reached the end of the tree
|
||||
if (!node.children) {
|
||||
node.children = [];
|
||||
}
|
||||
// Check if the node has children
|
||||
const childIds = parentLookupDb.childrenById[node.id];
|
||||
// If the node has children, add them to the node
|
||||
if (childIds) {
|
||||
childIds.forEach((childId) => {
|
||||
node.children.push(nodeDb[childId]);
|
||||
});
|
||||
}
|
||||
// Recursive call
|
||||
insertChildren(node.children, parentLookupDb);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Draws a flowchart in the tag with id: id based on the graph definition in text.
|
||||
*
|
||||
* @param text
|
||||
* @param id
|
||||
*/
|
||||
|
||||
export const draw = async function (text, id, _version, diagObj) {
|
||||
// Add temporary render element
|
||||
diagObj.db.clear();
|
||||
nodeDb = {};
|
||||
diagObj.db.setGen('gen-2');
|
||||
// Parse the graph definition
|
||||
diagObj.parser.parse(text);
|
||||
|
||||
const renderEl = select('body').append('div').attr('style', 'height:400px').attr('id', 'cy');
|
||||
let graph = {
|
||||
id: 'root',
|
||||
layoutOptions: {
|
||||
'elk.hierarchyHandling': 'INCLUDE_CHILDREN',
|
||||
'org.eclipse.elk.padding': '[top=100, left=100, bottom=110, right=110]',
|
||||
'elk.layered.spacing.edgeNodeBetweenLayers': '30',
|
||||
// 'elk.layered.mergeEdges': 'true',
|
||||
'elk.direction': 'DOWN',
|
||||
// 'elk.ports.sameLayerEdges': true,
|
||||
// 'nodePlacement.strategy': 'SIMPLE',
|
||||
},
|
||||
children: [],
|
||||
edges: [],
|
||||
};
|
||||
log.info('Drawing flowchart using v3 renderer', elk);
|
||||
|
||||
// Set the direction,
|
||||
// Fetch the default direction, use TD if none was found
|
||||
let dir = diagObj.db.getDirection();
|
||||
switch (dir) {
|
||||
case 'BT':
|
||||
graph.layoutOptions['elk.direction'] = 'UP';
|
||||
break;
|
||||
case 'TB':
|
||||
graph.layoutOptions['elk.direction'] = 'DOWN';
|
||||
break;
|
||||
case 'LR':
|
||||
graph.layoutOptions['elk.direction'] = 'RIGHT';
|
||||
break;
|
||||
case 'RL':
|
||||
graph.layoutOptions['elk.direction'] = 'LEFT';
|
||||
break;
|
||||
}
|
||||
const { securityLevel, flowchart: conf } = getConfig();
|
||||
|
||||
// Find the root dom node to ne used in rendering
|
||||
// Handle root and document for when rendering in sandbox mode
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
const svg = root.select(`[id="${id}"]`);
|
||||
|
||||
// Define the supported markers for the diagram
|
||||
const markers = ['point', 'circle', 'cross'];
|
||||
|
||||
// Add the marker definitions to the svg as marker tags
|
||||
insertMarkers(svg, markers, diagObj.type, diagObj.arrowMarkerAbsolute);
|
||||
|
||||
// Fetch the vertices/nodes and edges/links from the parsed graph definition
|
||||
const vert = diagObj.db.getVertices();
|
||||
|
||||
// Setup nodes from the subgraphs with type group, these will be used
|
||||
// as nodes with children in the subgraph
|
||||
let subG;
|
||||
const subGraphs = diagObj.db.getSubGraphs();
|
||||
log.info('Subgraphs - ', subGraphs);
|
||||
for (let i = subGraphs.length - 1; i >= 0; i--) {
|
||||
subG = subGraphs[i];
|
||||
diagObj.db.addVertex(subG.id, subG.title, 'group', undefined, subG.classes, subG.dir);
|
||||
}
|
||||
|
||||
// Add an element in the svg to be used to hold the subgraphs container
|
||||
// elements
|
||||
const subGraphsEl = svg.insert('g').attr('class', 'subgraphs');
|
||||
|
||||
// Create the lookup db for the subgraphs and their children to used when creating
|
||||
// the tree structured graph
|
||||
const parentLookupDb = addSubGraphs(diagObj.db);
|
||||
|
||||
// Add the nodes to the graph, this will entail creating the actual nodes
|
||||
// in order to get the size of the node. You can't get the size of a node
|
||||
// that is not in the dom so we need to add it to the dom, get the size
|
||||
// we will position the nodes when we get the layout from elkjs
|
||||
graph = addVertices(vert, id, root, doc, diagObj, parentLookupDb, graph);
|
||||
|
||||
// Time for the edges, we start with adding an element in the node to hold the edges
|
||||
const edgesEl = svg.insert('g').attr('class', 'edges edgePath');
|
||||
// Fetch the edges form the parsed graph definition
|
||||
const edges = diagObj.db.getEdges();
|
||||
|
||||
// Add the edges to the graph, this will entail creating the actual edges
|
||||
graph = addEdges(edges, diagObj, graph, svg);
|
||||
|
||||
// Iterate through all nodes and add the top level nodes to the graph
|
||||
const nodes = Object.keys(nodeDb);
|
||||
nodes.forEach((nodeId) => {
|
||||
const node = nodeDb[nodeId];
|
||||
if (!node.parent) {
|
||||
graph.children.push(node);
|
||||
}
|
||||
// Subgraph
|
||||
if (parentLookupDb.childrenById[nodeId] !== undefined) {
|
||||
node.labels = [
|
||||
{
|
||||
text: node.labelText,
|
||||
layoutOptions: {
|
||||
'nodeLabels.placement': '[H_CENTER, V_TOP, INSIDE]',
|
||||
},
|
||||
width: node.labelData.width,
|
||||
height: node.labelData.height,
|
||||
},
|
||||
];
|
||||
delete node.x;
|
||||
delete node.y;
|
||||
delete node.width;
|
||||
delete node.height;
|
||||
}
|
||||
});
|
||||
insertChildren(graph.children, parentLookupDb);
|
||||
log.info('after layout', JSON.stringify(graph, null, 2));
|
||||
const g = await elk.layout(graph);
|
||||
drawNodes(0, 0, g.children, svg, subGraphsEl, diagObj, 0);
|
||||
log.info('after layout', g);
|
||||
g.edges?.map((edge) => {
|
||||
insertEdge(edgesEl, edge, edge.edgeData, diagObj, parentLookupDb);
|
||||
});
|
||||
setupGraphViewbox({}, svg, conf.diagramPadding, conf.useMaxWidth);
|
||||
// Remove element after layout
|
||||
renderEl.remove();
|
||||
};
|
||||
|
||||
const drawNodes = (relX, relY, nodeArray, svg, subgraphsEl, diagObj, depth) => {
|
||||
nodeArray.forEach(function (node) {
|
||||
if (node) {
|
||||
nodeDb[node.id].offset = {
|
||||
posX: node.x + relX,
|
||||
posY: node.y + relY,
|
||||
x: relX,
|
||||
y: relY,
|
||||
depth,
|
||||
width: node.width,
|
||||
height: node.height,
|
||||
};
|
||||
if (node.type === 'group') {
|
||||
const subgraphEl = subgraphsEl.insert('g').attr('class', 'subgraph');
|
||||
subgraphEl
|
||||
.insert('rect')
|
||||
.attr('class', 'subgraph subgraph-lvl-' + (depth % 5) + ' node')
|
||||
.attr('x', node.x + relX)
|
||||
.attr('y', node.y + relY)
|
||||
.attr('width', node.width)
|
||||
.attr('height', node.height);
|
||||
const label = subgraphEl.insert('g').attr('class', 'label');
|
||||
label.attr(
|
||||
'transform',
|
||||
`translate(${node.labels[0].x + relX + node.x}, ${node.labels[0].y + relY + node.y})`
|
||||
);
|
||||
label.node().appendChild(node.labelData.labelNode);
|
||||
|
||||
log.info('Id (UGH)= ', node.type, node.labels);
|
||||
} else {
|
||||
log.info('Id (UGH)= ', node.id);
|
||||
node.el.attr(
|
||||
'transform',
|
||||
`translate(${node.x + relX + node.width / 2}, ${node.y + relY + node.height / 2})`
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
nodeArray.forEach(function (node) {
|
||||
if (node && node.type === 'group') {
|
||||
drawNodes(relX + node.x, relY + node.y, node.children, svg, subgraphsEl, diagObj, depth + 1);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export default {
|
||||
getClasses,
|
||||
draw,
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user