Merge branch 'release/10.6.0'

This commit is contained in:
Knut Sveidqvist 2023-10-25 13:35:58 +02:00
commit d7ec9e7b0d
136 changed files with 7871 additions and 3906 deletions

View File

@ -49,8 +49,10 @@ module.exports = {
'no-unused-vars': 'off', 'no-unused-vars': 'off',
'cypress/no-async-tests': 'off', 'cypress/no-async-tests': 'off',
'@typescript-eslint/consistent-type-imports': 'error', '@typescript-eslint/consistent-type-imports': 'error',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-floating-promises': 'error', '@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/no-misused-promises': 'error', '@typescript-eslint/no-misused-promises': 'error',
'@typescript-eslint/no-unused-vars': 'warn',
'@typescript-eslint/ban-ts-comment': [ '@typescript-eslint/ban-ts-comment': [
'error', 'error',
{ {

View File

@ -17,6 +17,9 @@ body:
- Use a clear and concise title - Use a clear and concise title
- Fill out the text fields with as much detail as possible. - Fill out the text fields with as much detail as possible.
- Never be shy to give us screenshots and/or code samples. It will help! - Never be shy to give us screenshots and/or code samples. It will help!
There is a chance that the bug is already fixed in the git `develop` branch, but is not released yet.
So please check in [Live Editor - Develop](https://develop.git.mermaid.live) before raising an issue.
- type: textarea - type: textarea
attributes: attributes:
label: Description label: Description
@ -43,7 +46,7 @@ body:
attributes: attributes:
label: Code Sample label: Code Sample
description: |- description: |-
If applicable, add the code sample or a link to the [Live Editor](https://mermaid.live). If applicable, add the code sample or a link to the [Live Editor - Develop](https://develop.git.mermaid.live).
Any text pasted here will be rendered as a Code block. Any text pasted here will be rendered as a Code block.
render: text render: text
- type: textarea - type: textarea

View File

@ -7,8 +7,14 @@ contact_links:
url: https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE url: https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE
about: Join our Community on Slack for Help and a casual chat. about: Join our Community on Slack for Help and a casual chat.
- name: Documentation - name: Documentation
url: https://mermaid-js.github.io url: https://mermaid.js.org
about: Read our documentation for all that Mermaid.js can offer. about: Read our documentation for all that Mermaid.js can offer.
- name: Live Editor - name: Live Editor
url: https://mermaid.live url: https://mermaid.live
about: Try the live editor to preview graphs in no time. about: Try the live editor to preview graphs in no time.
- name: Live Editor - Develop
url: https://develop.git.mermaid.live
about: Try unreleased changes in the develop branch.
- name: Live Editor - Next
url: https://next.git.mermaid.live
about: Try unreleased changes in the next branch.

View File

@ -18,6 +18,7 @@ const MERMAID_CONFIG_DIAGRAM_KEYS = [
'er', 'er',
'pie', 'pie',
'quadrantChart', 'quadrantChart',
'xyChart',
'requirement', 'requirement',
'mindmap', 'mindmap',
'timeline', 'timeline',

View File

@ -68,7 +68,7 @@ try {
### Init deprecated and InitThrowsErrors removed ### Init deprecated and InitThrowsErrors removed
The config passed to `init` was not being used eariler. The config passed to `init` was not being used earlier.
It will now be used. It will now be used.
The `init` function is deprecated and will be removed in the next major release. The `init` function is deprecated and will be removed in the next major release.
init currently works as a wrapper to `initialize` and `run`. init currently works as a wrapper to `initialize` and `run`.
@ -195,7 +195,7 @@ mermaid.run({
- "Cannot activate" in sequenceDiagram [\#647](https://github.com/knsv/mermaid/issues/647) - "Cannot activate" in sequenceDiagram [\#647](https://github.com/knsv/mermaid/issues/647)
- Link \("click" statement\) in flowchart does not work in exported SVG [\#646](https://github.com/knsv/mermaid/issues/646) - Link \("click" statement\) in flowchart does not work in exported SVG [\#646](https://github.com/knsv/mermaid/issues/646)
- How to pass styling [\#639](https://github.com/knsv/mermaid/issues/639) - How to pass styling [\#639](https://github.com/knsv/mermaid/issues/639)
- The live editor cant show seq diagram with notes for 8.0.0-alpha.3 [\#638](https://github.com/knsv/mermaid/issues/638) - The live editor can't show seq diagram with notes for 8.0.0-alpha.3 [\#638](https://github.com/knsv/mermaid/issues/638)
- import mermaid.css with ES6 + NPM [\#634](https://github.com/knsv/mermaid/issues/634) - import mermaid.css with ES6 + NPM [\#634](https://github.com/knsv/mermaid/issues/634)
- Actor line cuts through other elements [\#633](https://github.com/knsv/mermaid/issues/633) - Actor line cuts through other elements [\#633](https://github.com/knsv/mermaid/issues/633)
- Graph TD line out of the picture \(left side\) [\#630](https://github.com/knsv/mermaid/issues/630) - Graph TD line out of the picture \(left side\) [\#630](https://github.com/knsv/mermaid/issues/630)
@ -504,7 +504,7 @@ mermaid.run({
- Docs css: code hard to read [\#324](https://github.com/knsv/mermaid/issues/324) - Docs css: code hard to read [\#324](https://github.com/knsv/mermaid/issues/324)
- About Markpad integration [\#323](https://github.com/knsv/mermaid/issues/323) - About Markpad integration [\#323](https://github.com/knsv/mermaid/issues/323)
- How to link backwords in flowchat? [\#321](https://github.com/knsv/mermaid/issues/321) - How to link backwards in flowchat? [\#321](https://github.com/knsv/mermaid/issues/321)
- Help with editor [\#310](https://github.com/knsv/mermaid/issues/310) - Help with editor [\#310](https://github.com/knsv/mermaid/issues/310)
- +1 [\#293](https://github.com/knsv/mermaid/issues/293) - +1 [\#293](https://github.com/knsv/mermaid/issues/293)
- Basic chart does not render on Chome, but does in Firefox [\#290](https://github.com/knsv/mermaid/issues/290) - Basic chart does not render on Chome, but does in Firefox [\#290](https://github.com/knsv/mermaid/issues/290)
@ -619,7 +619,7 @@ mermaid.run({
- render to png from the cli does not display the marker-end arrow heads [\#181](https://github.com/knsv/mermaid/issues/181) - render to png from the cli does not display the marker-end arrow heads [\#181](https://github.com/knsv/mermaid/issues/181)
- Links in sequence diagrams [\#159](https://github.com/knsv/mermaid/issues/159) - Links in sequence diagrams [\#159](https://github.com/knsv/mermaid/issues/159)
- comment characters `%%` cause parse error [\#141](https://github.com/knsv/mermaid/issues/141) - comment characters `%%` cause parse error [\#141](https://github.com/knsv/mermaid/issues/141)
- Add a reversed assymetric shape [\#124](https://github.com/knsv/mermaid/issues/124) - Add a reversed asymmetric shape [\#124](https://github.com/knsv/mermaid/issues/124)
- Add syntax for double headed arrows [\#123](https://github.com/knsv/mermaid/issues/123) - Add syntax for double headed arrows [\#123](https://github.com/knsv/mermaid/issues/123)
- Support for font-awesome [\#49](https://github.com/knsv/mermaid/issues/49) - Support for font-awesome [\#49](https://github.com/knsv/mermaid/issues/49)
@ -659,7 +659,7 @@ mermaid.run({
- Auto linewrap for notes in sequence diagrams [\#178](https://github.com/knsv/mermaid/issues/178) - Auto linewrap for notes in sequence diagrams [\#178](https://github.com/knsv/mermaid/issues/178)
- Execute code after initialize [\#176](https://github.com/knsv/mermaid/issues/176) - Execute code after initialize [\#176](https://github.com/knsv/mermaid/issues/176)
- Autoscaling for all diagram types [\#175](https://github.com/knsv/mermaid/issues/175) - Autoscaling for all diagram types [\#175](https://github.com/knsv/mermaid/issues/175)
- Problem wit click event callback [\#174](https://github.com/knsv/mermaid/issues/174) - Problem with click event callback [\#174](https://github.com/knsv/mermaid/issues/174)
- How to escape characters? [\#170](https://github.com/knsv/mermaid/issues/170) - How to escape characters? [\#170](https://github.com/knsv/mermaid/issues/170)
- it can not work [\#167](https://github.com/knsv/mermaid/issues/167) - it can not work [\#167](https://github.com/knsv/mermaid/issues/167)
- UML Class diagram [\#154](https://github.com/knsv/mermaid/issues/154) - UML Class diagram [\#154](https://github.com/knsv/mermaid/issues/154)
@ -762,7 +762,7 @@ mermaid.run({
- subgraph background is black in rendered flowchart PNG via CLI [\#121](https://github.com/knsv/mermaid/issues/121) - 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) - Internet Explorer Support [\#99](https://github.com/knsv/mermaid/issues/99)
- Assymetric shapes not documented [\#82](https://github.com/knsv/mermaid/issues/82) - Asymmetric shapes not documented [\#82](https://github.com/knsv/mermaid/issues/82)
- NoModificationAllowedError [\#23](https://github.com/knsv/mermaid/issues/23) - NoModificationAllowedError [\#23](https://github.com/knsv/mermaid/issues/23)
- Improve arrows [\#3](https://github.com/knsv/mermaid/issues/3) - Improve arrows [\#3](https://github.com/knsv/mermaid/issues/3)
@ -908,7 +908,7 @@ mermaid.run({
- Question marks don't render properly with /dist/mermaid.full.min.js [\#30](https://github.com/knsv/mermaid/issues/30) - Question marks don't render properly with /dist/mermaid.full.min.js [\#30](https://github.com/knsv/mermaid/issues/30)
- Error with some characters [\#25](https://github.com/knsv/mermaid/issues/25) - Error with some characters [\#25](https://github.com/knsv/mermaid/issues/25)
- Provide parse function in browser widthout `require`? [\#21](https://github.com/knsv/mermaid/issues/21) - Provide parse function in browser without `require`? [\#21](https://github.com/knsv/mermaid/issues/21)
- Better label text support [\#18](https://github.com/knsv/mermaid/issues/18) - Better label text support [\#18](https://github.com/knsv/mermaid/issues/18)
- Cap-cased words break parser [\#8](https://github.com/knsv/mermaid/issues/8) - Cap-cased words break parser [\#8](https://github.com/knsv/mermaid/issues/8)

View File

@ -59,8 +59,8 @@ representative at an online or offline event.
## Enforcement ## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at security@mermaid.live reported to the community leaders responsible for enforcement at <security@mermaid.live>.
.
All complaints will be reviewed and investigated promptly and fairly. All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the All community leaders are obligated to respect the privacy and security of the

View File

@ -20,6 +20,9 @@ Generate diagrams from markdown-like text.
<p align="center"> <p align="center">
<a href="./README.zh-CN.md">简体中文</a> <a href="./README.zh-CN.md">简体中文</a>
</p> </p>
<p align="center">
Try Live Editor previews of future releases: <a href="https://develop.git.mermaid.live/" title="Try the mermaid version from the develop branch.">Develop</a> | <a href="https://next.git.mermaid.live/" title="Try the mermaid version from the next branch.">Next</a>
</p>
<br> <br>
<br> <br>
@ -31,7 +34,7 @@ Generate diagrams from markdown-like text.
[![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid) [![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid)
[![NPM Downloads](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid) [![NPM Downloads](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) [![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_) [![Twitter Follow](https://img.shields.io/badge/Social-mermaidjs__-blue?style=social&logo=X)](https://twitter.com/mermaidjs_)
<img src="./img/header.png" alt="" /> <img src="./img/header.png" alt="" />

View File

@ -12,7 +12,7 @@ Mermaid
<p> <p>
<p align="center"> <p align="center">
<a href="https://mermaid.live/"><b>Live Editor!</b></a> <a href="https://mermaid.live/"><b>实时编辑器!</b></a>
</p> </p>
<p align="center"> <p align="center">
<a href="https://mermaid.js.org">📖 文档</a> | <a href="https://mermaid.js.org/intro/">🚀 入门</a> | <a href="https://www.jsdelivr.com/package/npm/mermaid">🌐 CDN</a> | <a href="https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE" title="Slack invite">🙌 加入我们</a> <a href="https://mermaid.js.org">📖 文档</a> | <a href="https://mermaid.js.org/intro/">🚀 入门</a> | <a href="https://www.jsdelivr.com/package/npm/mermaid">🌐 CDN</a> | <a href="https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE" title="Slack invite">🙌 加入我们</a>
@ -21,6 +21,10 @@ Mermaid
<a href="./README.md">English</a> <a href="./README.md">English</a>
</p> </p>
<p align="center">
尝试未来版本的实时编辑器预览: <a href="https://develop.git.mermaid.live/" title="尝试来自develop分支的mermaid版本。">Develop</a> | <a href="https://next.git.mermaid.live/" title="尝试来自next分支的mermaid版本。">Next</a>
</p>
<br> <br>
<br> <br>
@ -31,7 +35,7 @@ Mermaid
[![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid) [![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid)
[![NPM Downloads](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid) [![NPM Downloads](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) [![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_) [![Twitter Follow](https://img.shields.io/badge/Social-mermaidjs__-blue?style=social&logo=X)](https://twitter.com/mermaidjs_)
<img src="./img/header.png" alt="" /> <img src="./img/header.png" alt="" />

View File

@ -156,6 +156,7 @@
"vitepress", "vitepress",
"vueuse", "vueuse",
"xlink", "xlink",
"xychart",
"yash", "yash",
"yokozuna", "yokozuna",
"zenuml", "zenuml",

View File

@ -1,4 +1,4 @@
import { imgSnapshotTest } from '../../helpers/util.ts'; import { imgSnapshotTest, urlSnapshotTest } from '../../helpers/util.ts';
describe('Configuration and directives - nodes should be light blue', () => { describe('Configuration and directives - nodes should be light blue', () => {
it('No config - use default', () => { it('No config - use default', () => {
@ -206,8 +206,7 @@ graph TD
describe('when rendering several diagrams', () => { describe('when rendering several diagrams', () => {
it('diagrams should not taint later diagrams', () => { it('diagrams should not taint later diagrams', () => {
const url = 'http://localhost:9000/theme-directives.html'; const url = 'http://localhost:9000/theme-directives.html';
cy.visit(url); urlSnapshotTest(url, {});
cy.matchImageSnapshot('conf-and-directives.spec-when-rendering-several-diagrams-diagram-1');
}); });
}); });
}); });

View File

@ -520,7 +520,15 @@ describe('Gantt diagram', () => {
); );
}); });
it('should render a gantt diagram with very large intervals, skipping excludes if interval > 5 years', () => { // TODO: fix it
//
// This test is skipped deliberately
// because it fails and blocks our development pipeline
// It was added as an attempt to fix gantt performance issues
//
// https://github.com/mermaid-js/mermaid/issues/3274
//
it.skip('should render a gantt diagram with very large intervals, skipping excludes if interval > 5 years', () => {
imgSnapshotTest( imgSnapshotTest(
`gantt `gantt
title A long Gantt Diagram title A long Gantt Diagram
@ -528,7 +536,6 @@ describe('Gantt diagram', () => {
axisFormat %m-%d axisFormat %m-%d
tickInterval 1day tickInterval 1day
excludes weekends excludes weekends
section Section section Section
A task : a1, 9999-10-01, 30d A task : a1, 9999-10-01, 30d
Another task : after a1, 20d Another task : after a1, 20d

View File

@ -26,7 +26,7 @@ describe('Git Graph diagram', () => {
`gitGraph `gitGraph
commit id: "Normal Commit" commit id: "Normal Commit"
commit id: "Reverse Commit" type: REVERSE commit id: "Reverse Commit" type: REVERSE
commit id: "Hightlight Commit" type: HIGHLIGHT commit id: "Highlight Commit" type: HIGHLIGHT
`, `,
{} {}
); );
@ -36,7 +36,7 @@ describe('Git Graph diagram', () => {
`gitGraph `gitGraph
commit id: "Normal Commit with tag" tag: "v1.0.0" commit id: "Normal Commit with tag" tag: "v1.0.0"
commit id: "Reverse Commit with tag" type: REVERSE tag: "RC_1" commit id: "Reverse Commit with tag" type: REVERSE tag: "RC_1"
commit id: "Hightlight Commit" type: HIGHLIGHT tag: "8.8.4" commit id: "Highlight Commit" type: HIGHLIGHT tag: "8.8.4"
`, `,
{} {}
); );
@ -102,7 +102,7 @@ describe('Git Graph diagram', () => {
{} {}
); );
}); });
it('8: should render a simple gitgraph with more than 8 branchs & overriding variables', () => { it('8: should render a simple gitgraph with more than 8 branches & overriding variables', () => {
imgSnapshotTest( imgSnapshotTest(
`%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { `%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': {
'gitBranchLabel0': '#ffffff', 'gitBranchLabel0': '#ffffff',
@ -358,7 +358,7 @@ gitGraph
`gitGraph TB: `gitGraph TB:
commit id: "Normal Commit" commit id: "Normal Commit"
commit id: "Reverse Commit" type: REVERSE commit id: "Reverse Commit" type: REVERSE
commit id: "Hightlight Commit" type: HIGHLIGHT commit id: "Highlight Commit" type: HIGHLIGHT
`, `,
{} {}
); );
@ -368,7 +368,7 @@ gitGraph
`gitGraph TB: `gitGraph TB:
commit id: "Normal Commit with tag" tag: "v1.0.0" commit id: "Normal Commit with tag" tag: "v1.0.0"
commit id: "Reverse Commit with tag" type: REVERSE tag: "RC_1" commit id: "Reverse Commit with tag" type: REVERSE tag: "RC_1"
commit id: "Hightlight Commit" type: HIGHLIGHT tag: "8.8.4" commit id: "Highlight Commit" type: HIGHLIGHT tag: "8.8.4"
`, `,
{} {}
); );
@ -434,7 +434,7 @@ gitGraph
{} {}
); );
}); });
it('22: should render a simple gitgraph with more than 8 branchs & overriding variables | Vertical Branch', () => { it('22: should render a simple gitgraph with more than 8 branches & overriding variables | Vertical Branch', () => {
imgSnapshotTest( imgSnapshotTest(
`%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { `%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': {
'gitBranchLabel0': '#ffffff', 'gitBranchLabel0': '#ffffff',

View File

@ -160,4 +160,70 @@ describe('Quadrant Chart', () => {
); );
cy.get('svg'); cy.get('svg');
}); });
it('should render x-axis labels in the center, if x-axis has two labels', () => {
imgSnapshotTest(
`
quadrantChart
title Reach and engagement of campaigns
x-axis Low Reach --> High Reach
y-axis Low Engagement
quadrant-1 We should expand
quadrant-2 Need to promote
quadrant-3 Re-evaluate
quadrant-4 May be improved
Campaign A: [0.3, 0.6]
Campaign B: [0.45, 0.23]
Campaign C: [0.57, 0.69]
Campaign D: [0.78, 0.34]
Campaign E: [0.40, 0.34]
Campaign F: [0.35, 0.78]
`,
{}
);
cy.get('svg');
});
it('should render y-axis labels in the center, if y-axis has two labels', () => {
imgSnapshotTest(
`
quadrantChart
title Reach and engagement of campaigns
x-axis Low Reach
y-axis Low Engagement --> High Engagement
quadrant-1 We should expand
quadrant-2 Need to promote
quadrant-3 Re-evaluate
quadrant-4 May be improved
Campaign A: [0.3, 0.6]
Campaign B: [0.45, 0.23]
Campaign C: [0.57, 0.69]
Campaign D: [0.78, 0.34]
Campaign E: [0.40, 0.34]
Campaign F: [0.35, 0.78]
`,
{}
);
cy.get('svg');
});
it('should render both axes labels on the left and bottom, if both axes have only one label', () => {
imgSnapshotTest(
`
quadrantChart
title Reach and engagement of campaigns
x-axis Reach -->
y-axis Engagement -->
quadrant-1 We should expand
quadrant-2 Need to promote
quadrant-3 Re-evaluate
quadrant-4 May be improved
Campaign A: [0.3, 0.6]
Campaign B: [0.45, 0.23]
Campaign C: [0.57, 0.69]
Campaign D: [0.78, 0.34]
Campaign E: [0.40, 0.34]
Campaign F: [0.35, 0.78]
`,
{}
);
cy.get('svg');
});
}); });

View File

@ -57,7 +57,7 @@ describe('Timeline diagram', () => {
{} {}
); );
}); });
it('5: should render a simple timeline with directive overriden colors', () => { it('5: should render a simple timeline with directive overridden colors', () => {
imgSnapshotTest( imgSnapshotTest(
` %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { ` %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': {
'cScale0': '#ff0000', 'cScale0': '#ff0000',

View File

@ -0,0 +1,322 @@
import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
describe('XY Chart', () => {
it('should render the simplest possible chart', () => {
imgSnapshotTest(
`
xychart-beta
line [10, 30, 20]
`,
{}
);
cy.get('svg');
});
it('Should render a complete chart', () => {
imgSnapshotTest(
`
xychart-beta
title "Sales Revenue"
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`,
{}
);
});
it('Should render a chart without title', () => {
imgSnapshotTest(
`
xychart-beta
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`,
{}
);
cy.get('svg');
});
it('y-axis title not required', () => {
imgSnapshotTest(
`
xychart-beta
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`,
{}
);
cy.get('svg');
});
it('Should render a chart without y-axis with different range', () => {
imgSnapshotTest(
`
xychart-beta
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
bar [5000, 6000, 7500, 8200, 9500, 10500, 14000, 3200, 9200, 9900, 3400, 6000]
line [2000, 7000, 6500, 9200, 9500, 7500, 11000, 10200, 3200, 8500, 7000, 8800]
`,
{}
);
cy.get('svg');
});
it('x axis title not required', () => {
imgSnapshotTest(
`
xychart-beta
x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
bar [5000, 6000, 7500, 8200, 9500, 10500, 14000, 3200, 9200, 9900, 3400, 6000]
line [2000, 7000, 6500, 9200, 9500, 7500, 11000, 10200, 3200, 8500, 7000, 8800]
`,
{}
);
cy.get('svg');
});
it('Multiple plots can be rendered', () => {
imgSnapshotTest(
`
xychart-beta
line [23, 46, 77, 34]
line [45, 32, 33, 12]
bar [87, 54, 99, 85]
line [78, 88, 22, 4]
line [22, 29, 75, 33]
bar [52, 96, 35, 10]
`,
{}
);
cy.get('svg');
});
it('Decimals and negative numbers are supported', () => {
imgSnapshotTest(
`
xychart-beta
y-axis -2.4 --> 3.5
line [+1.3, .6, 2.4, -.34]
`,
{}
);
cy.get('svg');
});
it('Render spark line with "plotReservedSpacePercent"', () => {
imgSnapshotTest(
`
---
config:
theme: dark
xyChart:
width: 200
height: 20
plotReservedSpacePercent: 100
---
xychart-beta
line [5000, 9000, 7500, 6200, 9500, 5500, 11000, 8200, 9200, 9500, 7000, 8800]
`,
{}
);
cy.get('svg');
});
it('Render spark bar without displaying other property', () => {
imgSnapshotTest(
`
---
config:
theme: dark
xyChart:
width: 200
height: 20
xAxis:
showLabel: false
showTitle: false
showTick: false
showAxisLine: false
yAxis:
showLabel: false
showTitle: false
showTick: false
showAxisLine: false
---
xychart-beta
bar [5000, 9000, 7500, 6200, 9500, 5500, 11000, 8200, 9200, 9500, 7000, 8800]
`,
{}
);
cy.get('svg');
});
it('Should use all the config from directive', () => {
imgSnapshotTest(
`
%%{init: {"xyChart": {"width": 1000, "height": 600, "titlePadding": 5, "titleFontSize": 10, "xAxis": {"labelFontSize": "20", "labelPadding": 10, "titleFontSize": 30, "titlePadding": 20, "tickLength": 10, "tickWidth": 5}, "yAxis": {"labelFontSize": "20", "labelPadding": 10, "titleFontSize": 30, "titlePadding": 20, "tickLength": 10, "tickWidth": 5}, "plotBorderWidth": 5, "chartOrientation": "horizontal", "plotReservedSpacePercent": 60 }}}%%
xychart-beta
title "Sales Revenue"
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`,
{}
);
cy.get('svg');
});
it('Should use all the config from yaml', () => {
imgSnapshotTest(
`
---
config:
theme: forest
xyChart:
width: 1000
height: 600
titlePadding: 5
titleFontSize: 10
xAxis:
labelFontSize: 20
labelPadding: 10
titleFontSize: 30
titlePadding: 20
tickLength: 10
tickWidth: 5
axisLineWidth: 5
yAxis:
labelFontSize: 20
labelPadding: 10
titleFontSize: 30
titlePadding: 20
tickLength: 10
tickWidth: 5
axisLineWidth: 5
chartOrientation: horizontal
plotReservedSpacePercent: 60
---
xychart-beta
title "Sales Revenue"
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`,
{}
);
cy.get('svg');
});
it('Render with show axis title false', () => {
imgSnapshotTest(
`
---
config:
xyChart:
xAxis:
showTitle: false
yAxis:
showTitle: false
---
xychart-beta
title "Sales Revenue"
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`,
{}
);
cy.get('svg');
});
it('Render with show axis label false', () => {
imgSnapshotTest(
`
---
config:
xyChart:
xAxis:
showLabel: false
yAxis:
showLabel: false
---
xychart-beta
title "Sales Revenue"
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`,
{}
);
cy.get('svg');
});
it('Render with show axis tick false', () => {
imgSnapshotTest(
`
---
config:
xyChart:
xAxis:
showTick: false
yAxis:
showTick: false
---
xychart-beta
title "Sales Revenue"
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`,
{}
);
cy.get('svg');
});
it('Render with show axis line false', () => {
imgSnapshotTest(
`
---
config:
xyChart:
xAxis:
showAxisLine: false
yAxis:
showAxisLine: false
---
xychart-beta
title "Sales Revenue"
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`,
{}
);
cy.get('svg');
});
it('Render all the theme color', () => {
imgSnapshotTest(
`
---
config:
themeVariables:
xyChart:
titleColor: "#ff0000"
backgroundColor: "#f0f8ff"
yAxisLabelColor: "#ee82ee"
yAxisTitleColor: "#7fffd4"
yAxisTickColor: "#87ceeb"
yAxisLineColor: "#ff6347"
xAxisLabelColor: "#7fffd4"
xAxisTitleColor: "#ee82ee"
xAxisTickColor: "#ff6347"
xAxisLineColor: "#87ceeb"
plotColorPalette: "#008000, #faba63"
---
xychart-beta
title "Sales Revenue"
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`,
{}
);
cy.get('svg');
});
});

File diff suppressed because one or more lines are too long

View File

@ -58,10 +58,19 @@
</head> </head>
<body> <body>
<pre id="diagram" class="mermaid"> <pre id="diagram" class="mermaid">
flowchart-elk LR flowchart TB
subgraph example C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z & A1 & A2 & A3 & A4 & A5 & A6 & A7 & A8
node ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
end C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z & A1 & A2 & A3 & A4 & A5 & A6 & A7 & A8
</pre>
<pre id="diagram" class="mermaid2">
flowchart TB
A & A & A & A & A & A & A & A ---> C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z
</pre>
<pre id="diagram" class="mermaid2">
flowchart TB
A1 & A2 & A3 & A4 & A5 & A6 & A7 & A8 --> C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z
</pre> </pre>
<pre id="diagram" class="mermaid2"> <pre id="diagram" class="mermaid2">
flowchart flowchart
@ -441,6 +450,7 @@ mindmap
messageFontFamily: 'courier', messageFontFamily: 'courier',
}, },
fontSize: 16, fontSize: 16,
logLevel: 0,
}); });
function callback() { function callback() {
alert('It worked'); alert('It worked');

View File

@ -42,7 +42,8 @@
</pre> </pre>
<script type="module"> <script type="module">
import mermaid from './mermaid.esm.mjs'; import mermaid from './mermaid.esm.mjs';
mermaid.initialize({ startOnLoad: true, logLevel: 0 }); mermaid.initialize({ startOnLoad: false, logLevel: 0 });
await mermaid.run();
if (window.Cypress) { if (window.Cypress) {
window.rendered = true; window.rendered = true;

View File

@ -1,15 +1,6 @@
<html> <html>
<head> <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 href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
/>
<link
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
rel="stylesheet"
/>
<style> <style>
body { body {
/* background: rgb(221, 208, 208); */ /* background: rgb(221, 208, 208); */
@ -122,26 +113,21 @@
<script type="module"> <script type="module">
import mermaid from './mermaid.esm.mjs'; import mermaid from './mermaid.esm.mjs';
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
};
mermaid.initialize({ mermaid.initialize({
// theme: 'dark',
// theme: 'dark',
// arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 0, logLevel: 0,
// flowchart: { useMaxWidth: true },
graph: { curve: 'cardinal', htmlLabels: false }, graph: { curve: 'cardinal', htmlLabels: false },
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50, showSequenceNumbers: true }, sequence: { actorMargin: 50, showSequenceNumbers: true },
// sequenceDiagram: { actorMargin: 300 } // deprecated
fontFamily: '"arial", sans-serif', fontFamily: '"arial", sans-serif',
curve: 'cardinal', curve: 'cardinal',
securityLevel: 'strict', securityLevel: 'strict',
startOnLoad: false,
}); });
function callback() {
alert('It worked'); await mermaid.run();
if (window.Cypress) {
window.rendered = true;
} }
</script> </script>
</body> </body>

View File

@ -173,7 +173,7 @@
Container(mobile, "Mobile App", "Xamarin", "Provides a limited subset of the Internet Banking functionality to customers via their mobile device.") Container(mobile, "Mobile App", "Xamarin", "Provides a limited subset of the Internet Banking functionality to customers via their mobile device.")
} }
Deployment_Node(comp, "Customer's computer", "Mircosoft Windows or Apple macOS"){ Deployment_Node(comp, "Customer's computer", "Microsoft Windows or Apple macOS"){
Deployment_Node(browser, "Web Browser", "Google Chrome, Mozilla Firefox,<br/> Apple Safari or Microsoft Edge"){ Deployment_Node(browser, "Web Browser", "Google Chrome, Mozilla Firefox,<br/> Apple Safari or Microsoft Edge"){
Container(spa, "Single Page Application", "JavaScript and Angular", "Provides all of the Internet Banking functionality to customers via their web browser.") Container(spa, "Single Page Application", "JavaScript and Angular", "Provides all of the Internet Banking functionality to customers via their web browser.")
} }

View File

@ -22,7 +22,7 @@
--- ---
graph LR graph LR
accTitle: This is a complicated flow accTitle: This is a complicated flow
accDescr: This is the descriptoin for the complicated flow. accDescr: This is the description for the complicated flow.
sid-B3655226-6C29-4D00-B685-3D5C734DC7E1[" sid-B3655226-6C29-4D00-B685-3D5C734DC7E1["

View File

@ -60,6 +60,9 @@
<li> <li>
<h2><a href="./quadrantchart.html">Quadrant charts</a></h2> <h2><a href="./quadrantchart.html">Quadrant charts</a></h2>
</li> </li>
<li>
<h2><a href="./xychart.html">XY charts</a></h2>
</li>
<li> <li>
<h2><a href="./requirements.html">Requirements</a></h2> <h2><a href="./requirements.html">Requirements</a></h2>
</li> </li>

View File

@ -17,7 +17,7 @@
<h1>Requirement diagram demos</h1> <h1>Requirement diagram demos</h1>
<pre class="mermaid"> <pre class="mermaid">
requirementDiagram requirementDiagram
accTitle: Requirments demo in black and white accTitle: Requirements demo in black and white
accDescr: A series of requirement boxes showing relationships among them. Has meaningless task names accDescr: A series of requirement boxes showing relationships among them. Has meaningless task names
requirement test_req { requirement test_req {

View File

@ -183,7 +183,7 @@
</pre> </pre>
<hr /> <hr />
<h2>Compsite states can link to themselves</h2> <h2>Composite states can link to themselves</h2>
<pre class="mermaid"> <pre class="mermaid">
stateDiagram-v2 stateDiagram-v2
state Active { state Active {
@ -199,7 +199,7 @@
stateDiagram-v2 stateDiagram-v2
[*] --> S1 [*] --> S1
S1 --> S2: This long line uses a br tag<br />to create multiple<br />lines. S1 --> S2: This long line uses a br tag<br />to create multiple<br />lines.
S1 --> S3: This transition descripton uses \na newline character\nto create multiple\nlines. S1 --> S3: This transition description uses \na newline character\nto create multiple\nlines.
</pre> </pre>
<hr /> <hr />

184
demos/xychart.html Normal file
View File

@ -0,0 +1,184 @@
<!DOCTYPE html>
<html lang="en">
<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>
<h1>XY Charts demos</h1>
<pre class="mermaid">
xychart-beta
title "Sales Revenue (in $)"
x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
</pre>
<hr />
<h1>XY Charts horizontal</h1>
<pre class="mermaid">
xychart-beta horizontal
title "Basic xychart"
x-axis "this is x axis" [category1, "category 2", category3, category4]
y-axis yaxisText 10 --> 150
bar "sample bat" [52, 96, 35, 10]
line [23, 46, 75, 43]
</pre>
<hr />
<h1>XY Charts only lines and bar</h1>
<pre class="mermaid">
xychart-beta
line [23, 46, 77, 34]
line [45, 32, 33, 12]
line [87, 54, 99, 85]
line [78, 88, 22, 4]
line [22, 29, 75, 33]
bar [52, 96, 35, 10]
</pre>
<hr />
<h1>XY Charts with +ve and -ve numbers</h1>
<pre class="mermaid">
xychart-beta
line [+1.3, .6, 2.4, -.34]
</pre>
<h1>XY Charts Bar with multiple category</h1>
<pre class="mermaid">
xychart-beta
title "Basic xychart with many categories"
x-axis "this is x axis" [category1, "category 2", category3, category4, category5, category6, category7]
y-axis yaxisText 10 --> 150
bar "sample bar" [52, 96, 35, 10, 87, 34, 67, 99]
</pre>
<h1>XY Charts line with multiple category</h1>
<pre class="mermaid">
xychart-beta
title "Line chart with many category"
x-axis "this is x axis" [category1, "category 2", category3, category4, category5, category6, category7]
y-axis yaxisText 10 --> 150
line "sample line" [52, 96, 35, 10, 87, 34, 67, 99]
</pre>
<h1>XY Charts category with large text</h1>
<pre class="mermaid">
xychart-beta
title "Basic xychart with many categories with category overlap"
x-axis "this is x axis" [category1, "Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat.", category3, category4, category5, category6, category7]
y-axis yaxisText 10 --> 150
bar "sample bar" [52, 96, 35, 10, 87, 34, 67, 99]
</pre>
<h1>sparkline demo</h1>
<pre class="mermaid">
---
config:
theme: dark
xyChart:
width: 200
height: 20
plotReservedSpacePercent: 100
---
xychart-beta
line [5000, 9000, 7500, 6200, 9500, 5500, 11000, 8200, 9200, 9500, 7000, 8800]
</pre>
<h1>sparkBar demo</h1>
<pre class="mermaid">
---
config:
theme: dark
xyChart:
width: 200
height: 20
plotReservedSpacePercent: 100
---
xychart-beta
bar [5000, 9000, 7500, 6200, 9500, 5500, 11000, 8200, 9200, 9500, 7000, 8800]
</pre>
<h1>XY Charts demos with all configs</h1>
<pre class="mermaid">
---
config:
theme: forest
xyChart:
width: 1000
height: 600
titlePadding: 5
titleFontSize: 10
xAxis:
labelFontSize: 20
labelPadding: 10
titleFontSize: 30
titlePadding: 20
tickLength: 10
tickWidth: 5
axisLineWidth: 5
yAxis:
labelFontSize: 20
labelPadding: 10
titleFontSize: 30
titlePadding: 20
tickLength: 10
tickWidth: 5
axisLineWidth: 5
chartOrientation: horizontal
plotReservedSpacePercent: 60
---
xychart-beta
title "Sales Revene"
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
</pre>
<h1>XY Charts demos with all theme config</h1>
<pre class="mermaid">
---
config:
themeVariables:
xyChart:
titleColor: "#ff0000"
backgroundColor: "#f0f8ff"
yAxisLabelColor: "#ee82ee"
yAxisTitleColor: "#7fffd4"
yAxisTickColor: "#87ceeb"
yAxisLineColor: "#ff6347"
xAxisLabelColor: "#7fffd4"
xAxisTitleColor: "#ee82ee"
xAxisTickColor: "#ff6347"
xAxisLineColor: "#87ceeb"
plotColorPalette: "#008000, #faba63"
---
xychart-beta
title "Sales Revene"
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
</pre>
<hr />
<script type="module">
import mermaid from './mermaid.esm.mjs';
mermaid.initialize({
theme: 'default',
logLevel: 3,
securityLevel: 'loose',
});
</script>
</body>
</html>

View File

@ -1,7 +1,7 @@
version: '3.9' version: '3.9'
services: services:
mermaid: mermaid:
image: node:18.17.1-alpine3.18 image: node:18.18.2-alpine3.18
stdin_open: true stdin_open: true
tty: true tty: true
working_dir: /mermaid working_dir: /mermaid

View File

@ -97,7 +97,7 @@ See [the accTitle and accDescr usage examples](#acctitle-and-accdescr-usage-exam
graph LR graph LR
accTitle: Big Decisions accTitle: Big Decisions
accDescr: Bob's Burgers process for making big decisions accDescr: Bob's Burgers process for making big decisions
A[Identify Big Descision] --> B{Make Big Decision} A[Identify Big Decision] --> B{Make Big Decision}
B --> D[Be done] B --> D[Be done]
``` ```
@ -105,7 +105,7 @@ See [the accTitle and accDescr usage examples](#acctitle-and-accdescr-usage-exam
graph LR graph LR
accTitle: Big Decisions accTitle: Big Decisions
accDescr: Bob's Burgers process for making big decisions accDescr: Bob's Burgers process for making big decisions
A[Identify Big Descision] --> B{Make Big Decision} A[Identify Big Decision] --> B{Make Big Decision}
B --> D[Be done] B --> D[Be done]
``` ```
@ -137,7 +137,7 @@ Here is the HTML generated for the SVG element: _(Note that some of the SVG attr
for making very, very big decisions. for making very, very big decisions.
This is actually a very simple flow: identify the big decision and then make the big decision. This is actually a very simple flow: identify the big decision and then make the big decision.
} }
A[Identify Big Descision] --> B{Make Big Decision} A[Identify Big Decision] --> B{Make Big Decision}
B --> D[Be done] B --> D[Be done]
``` ```
@ -149,7 +149,7 @@ Here is the HTML generated for the SVG element: _(Note that some of the SVG attr
for making very, very big decisions. for making very, very big decisions.
This is actually a very simple flow: identify the big decision and then make the big decision. This is actually a very simple flow: identify the big decision and then make the big decision.
} }
A[Identify Big Descision] --> B{Make Big Decision} A[Identify Big Decision] --> B{Make Big Decision}
B --> D[Be done] B --> D[Be done]
``` ```

View File

@ -14,7 +14,7 @@
#### Defined in #### Defined in
[defaultConfig.ts:268](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L268) [defaultConfig.ts:272](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L272)
--- ---

View File

@ -41,6 +41,8 @@ Below are a list of community plugins and integrations created with Mermaid.
- [Mermaid plugin for GitBook](https://github.com/wwformat/gitbook-plugin-mermaid-pdf) - [Mermaid plugin for GitBook](https://github.com/wwformat/gitbook-plugin-mermaid-pdf)
- [LiveBook](https://livebook.dev) ✅ - [LiveBook](https://livebook.dev) ✅
- [Atlassian Products](https://www.atlassian.com) - [Atlassian Products](https://www.atlassian.com)
- [Mermaid Charts & Diagrams for Confluence](https://marketplace.atlassian.com/apps/1222572/)
- [Mermaid Charts & Diagrams for Jira](https://marketplace.atlassian.com/apps/1224537/)
- [Mermaid Live Editor for Confluence Cloud](https://marketplace.atlassian.com/apps/1231571/mermaid-live-editor-for-confluence?hosting=cloud&tab=overview) - [Mermaid Live Editor for Confluence Cloud](https://marketplace.atlassian.com/apps/1231571/mermaid-live-editor-for-confluence?hosting=cloud&tab=overview)
- [Mermaid Plugin for Confluence](https://marketplace.atlassian.com/apps/1214124/mermaid-plugin-for-confluence?hosting=server&tab=overview) - [Mermaid Plugin for Confluence](https://marketplace.atlassian.com/apps/1214124/mermaid-plugin-for-confluence?hosting=server&tab=overview)
- [CloudScript.io Addon](https://marketplace.atlassian.com/apps/1219878/cloudscript-io-mermaid-addon?hosting=cloud&tab=overview) - [CloudScript.io Addon](https://marketplace.atlassian.com/apps/1219878/cloudscript-io-mermaid-addon?hosting=cloud&tab=overview)
@ -49,7 +51,7 @@ Below are a list of community plugins and integrations created with Mermaid.
- [Mermaid Macro](https://www.redmine.org/plugins/redmine_mermaid_macro) - [Mermaid Macro](https://www.redmine.org/plugins/redmine_mermaid_macro)
- [redmine-mermaid](https://github.com/styz/redmine_mermaid) - [redmine-mermaid](https://github.com/styz/redmine_mermaid)
- [markdown-for-mermaid-plugin](https://github.com/jamieh-mongolian/markdown-for-mermaid-plugin) - [markdown-for-mermaid-plugin](https://github.com/jamieh-mongolian/markdown-for-mermaid-plugin)
- [JetBrains IDE eg Pycharm](https://www.jetbrains.com/go/guide/tips/mermaid-js-support-in-markdown/) - [Mermaid Plugin for JetBrains IDEs](https://plugins.jetbrains.com/plugin/20146-mermaid)
- [mermerd](https://github.com/KarnerTh/mermerd) - [mermerd](https://github.com/KarnerTh/mermerd)
- Visual Studio Code [Polyglot Interactive Notebooks](https://github.com/dotnet/interactive#net-interactive) - Visual Studio Code [Polyglot Interactive Notebooks](https://github.com/dotnet/interactive#net-interactive)
@ -173,7 +175,7 @@ Communication tools and platforms
- [remark](https://remark.js.org/) - [remark](https://remark.js.org/)
- [remark-mermaidjs](https://github.com/remcohaszing/remark-mermaidjs) - [remark-mermaidjs](https://github.com/remcohaszing/remark-mermaidjs)
- [rehype](https://github.com/rehypejs/rehype) - [rehype](https://github.com/rehypejs/rehype)
- [rehype-mermaidjs](https://github.com/remcohaszing/rehype-mermaidjs) - [rehype-mermaid](https://github.com/remcohaszing/rehype-mermaid)
- [Gatsby](https://www.gatsbyjs.com/) - [Gatsby](https://www.gatsbyjs.com/)
- [gatsby-remark-mermaid](https://github.com/remcohaszing/gatsby-remark-mermaid) - [gatsby-remark-mermaid](https://github.com/remcohaszing/gatsby-remark-mermaid)
- [JSDoc](https://jsdoc.app/) - [JSDoc](https://jsdoc.app/)

View File

@ -283,6 +283,26 @@ quadrantChart
Campaign F: [0.35, 0.78] Campaign F: [0.35, 0.78]
``` ```
### [XY Chart](../syntax/xyChart.md)
```mermaid-example
xychart-beta
title "Sales Revenue"
x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
```
```mermaid
xychart-beta
title "Sales Revenue"
x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
```
## Installation ## Installation
**In depth guides and examples can be found at [Getting Started](./getting-started.md) and [Usage](../config/usage.md).** **In depth guides and examples can be found at [Getting Started](./getting-started.md) and [Usage](../config/usage.md).**

View File

@ -764,7 +764,7 @@ flowchart LR
end end
%% ^ These subgraphs are identical, except for the links to them: %% ^ These subgraphs are identical, except for the links to them:
%% Link *to* subgraph1: subgraph1 direction is mantained %% Link *to* subgraph1: subgraph1 direction is maintained
outside --> subgraph1 outside --> subgraph1
%% Link *within* subgraph2: %% Link *within* subgraph2:
%% subgraph2 inherits the direction of the top-level graph (LR) %% subgraph2 inherits the direction of the top-level graph (LR)
@ -783,7 +783,7 @@ flowchart LR
end end
%% ^ These subgraphs are identical, except for the links to them: %% ^ These subgraphs are identical, except for the links to them:
%% Link *to* subgraph1: subgraph1 direction is mantained %% Link *to* subgraph1: subgraph1 direction is maintained
outside --> subgraph1 outside --> subgraph1
%% Link *within* subgraph2: %% Link *within* subgraph2:
%% subgraph2 inherits the direction of the top-level graph (LR) %% subgraph2 inherits the direction of the top-level graph (LR)
@ -1112,7 +1112,7 @@ flowchart TD
B-->E(A fa:fa-camera-retro perhaps?) B-->E(A fa:fa-camera-retro perhaps?)
``` ```
Mermaid is compatible with Font Awesome up to verion 5, Free icons only. Check that the icons you use are from the [supported set of icons](https://fontawesome.com/v5/search?o=r&m=free). Mermaid is compatible with Font Awesome up to version 5, Free icons only. Check that the icons you use are from the [supported set of icons](https://fontawesome.com/v5/search?o=r&m=free).
## Graph declarations with spaces between vertices and link and without semicolon ## Graph declarations with spaces between vertices and link and without semicolon
@ -1146,7 +1146,7 @@ The layout of the diagram is done with the renderer. The default renderer is dag
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. 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. The _elk_ renderer is an experimental feature.
You can change the renderer to elk by adding this directive: You can change the renderer to elk by adding this directive:
%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%% %%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%

View File

@ -827,18 +827,25 @@ Here, we have changed the default main branch name to `MetroLine1`.
## Orientation (v10.3.0+) ## Orientation (v10.3.0+)
In Mermaid, the default orientation is Left to Right. The branches are lined vertically. Mermaid supports two graph orientations: **Left-to-Right** (default) and **Top-to-Bottom**.
You can set this with either `LR:` (for [**Left-to-Right**](#left-to-right-default-lr)) or `TB:` (for [**Top-to-Bottom**](#top-to-bottom-tb)) after `gitGraph`.
### Left to Right (default, `LR:`)
In Mermaid, the default orientation is for commits to run from left to right and for branches to be stacked on top of one another.
However, you can set this explicitly with `LR:` after `gitGraph`.
Usage example: Usage example:
```mermaid-example ```mermaid-example
gitGraph gitGraph LR:
commit commit
commit commit
branch develop branch develop
commit commit
commit commit
commit
checkout main checkout main
commit commit
commit commit
@ -848,13 +855,12 @@ Usage example:
``` ```
```mermaid ```mermaid
gitGraph gitGraph LR:
commit commit
commit commit
branch develop branch develop
commit commit
commit commit
commit
checkout main checkout main
commit commit
commit commit
@ -863,9 +869,11 @@ Usage example:
commit commit
``` ```
Sometimes we may want to change the orientation. Currently, Mermaid supports two orientations: **Left to Right**(default) and **Top to Bottom**. ### Top to Bottom (`TB:`)
In order to change the orientation from top to bottom i.e. branches lined horizontally, you need to add `TB` along with `gitGraph`. In `TB` (**Top-to-Bottom**) orientation, the commits run from top to bottom of the graph and branches are arranged side-by-side.
To orient the graph this way, you need to add `TB:` after gitGraph.
Usage example: Usage example:
@ -876,7 +884,6 @@ Usage example:
branch develop branch develop
commit commit
commit commit
commit
checkout main checkout main
commit commit
commit commit
@ -892,7 +899,6 @@ Usage example:
branch develop branch develop
commit commit
commit commit
commit
checkout main checkout main
commit commit
commit commit

View File

@ -102,26 +102,26 @@ Points are used to plot a circle inside the quadrantChart. The syntax is `<text>
## Chart Configurations ## Chart Configurations
| Parameter | Description | Default value | | Parameter | Description | Default value |
| --------------------------------- | ------------------------------------------------------------------------------------------------- | :-----------: | | --------------------------------- | -------------------------------------------------------------------------------------------------- | :-----------: |
| chartWidth | Width of the chart | 500 | | chartWidth | Width of the chart | 500 |
| chartHeight | Height of the chart | 500 | | chartHeight | Height of the chart | 500 |
| titlePadding | Top and Bottom padding of the title | 10 | | titlePadding | Top and Bottom padding of the title | 10 |
| titleFontSize | Title font size | 20 | | titleFontSize | Title font size | 20 |
| quadrantPadding | Padding outside all the quadrants | 5 | | quadrantPadding | Padding outside all the quadrants | 5 |
| quadrantTextTopPadding | Quadrant text top padding when text is drawn on top ( not data points are there) | 5 | | quadrantTextTopPadding | Quadrant text top padding when text is drawn on top ( not data points are there) | 5 |
| quadrantLabelFontSize | Quadrant text font size | 16 | | quadrantLabelFontSize | Quadrant text font size | 16 |
| quadrantInternalBorderStrokeWidth | Border stroke width inside the quadrants | 1 | | quadrantInternalBorderStrokeWidth | Border stroke width inside the quadrants | 1 |
| quadrantExternalBorderStrokeWidth | Quadrant external border stroke width | 2 | | quadrantExternalBorderStrokeWidth | Quadrant external border stroke width | 2 |
| xAxisLabelPadding | Top and bottom padding of x-axis text | 5 | | xAxisLabelPadding | Top and bottom padding of x-axis text | 5 |
| xAxisLabelFontSize | X-axis texts font size | 16 | | xAxisLabelFontSize | X-axis texts font size | 16 |
| xAxisPosition | Position of x-axis (top , bottom) if there are points the x-axis will alway be rendered in bottom | 'top' | | xAxisPosition | Position of x-axis (top , bottom) if there are points the x-axis will always be rendered in bottom | 'top' |
| yAxisLabelPadding | Left and Right padding of y-axis text | 5 | | yAxisLabelPadding | Left and Right padding of y-axis text | 5 |
| yAxisLabelFontSize | Y-axis texts font size | 16 | | yAxisLabelFontSize | Y-axis texts font size | 16 |
| yAxisPosition | Position of y-axis (left , right) | 'left' | | yAxisPosition | Position of y-axis (left , right) | 'left' |
| pointTextPadding | Padding between point and the below text | 5 | | pointTextPadding | Padding between point and the below text | 5 |
| pointLabelFontSize | Point text font size | 12 | | pointLabelFontSize | Point text font size | 12 |
| pointRadius | Radius of the point to be drawn | 5 | | pointRadius | Radius of the point to be drawn | 5 |
## Chart Theme Variables ## Chart Theme Variables

View File

@ -217,7 +217,7 @@ Note that there are no sections defined, and each time period and its correspond
2. Disable the multiColor option using the `disableMultiColor` option. This will make all time periods and events follow the same 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. You will need to add this option either via mermaid.initialize function or directives.
```javascript ```javascript
mermaid.initialize({ mermaid.initialize({

188
docs/syntax/xyChart.md Normal file
View File

@ -0,0 +1,188 @@
> **Warning**
>
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
>
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/syntax/xyChart.md](../../packages/mermaid/src/docs/syntax/xyChart.md).
# XY Chart
> In the context of mermaid-js, the XY chart is a comprehensive charting module that encompasses various types of charts that utilize both x-axis and y-axis for data representation. Presently, it includes two fundamental chart types: the bar chart and the line chart. These charts are designed to visually display and analyze data that involve two numerical variables.
> It's important to note that while the current implementation of mermaid-js includes these two chart types, the framework is designed to be dynamic and adaptable. Therefore, it has the capacity for expansion and the inclusion of additional chart types in the future. This means that users can expect an evolving suite of charting options within the XY chart module, catering to various data visualization needs as new chart types are introduced over time.
## Example
```mermaid-example
xychart-beta
title "Sales Revenue"
x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
```
```mermaid
xychart-beta
title "Sales Revenue"
x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
```
## Syntax
> **Note**
> All text values that contain only one word can be written without `"`. If a text value has many words in it, specifically if it contains spaces, enclose the value in `"`
### Orientations
The chart can be drawn horizontal or vertical, default value is vertical.
xychart-beta horizontal
...
### Title
The title is a short description of the chart and it will always render on top of the chart.
#### Example
xychart-beta
title "This is a simple example"
...
> **Note**
> If the title is a single word one no need to use `"`, but if it has space `"` is needed
### x-axis
The x-axis primarily serves as a categorical value, although it can also function as a numeric range value when needed.
#### Example
1. `x-axis title min --> max` x-axis will function as numeric with the given range
2. `x-axis "title with space" [cat1, "cat2 with space", cat3]` x-axis if categorical, categories are text type
### y-axis
The y-axis is employed to represent numerical range values, it cannot have categorical values.
#### Example
1. `y-axis title min --> max`
2. `y-axis title` it will only add the title, the range will be auto generated from data.
> **Note**
> Both x and y axis are optional if not provided we will try to create the range
### Line chart
A line chart offers the capability to graphically depict lines.
#### Example
1. `line [2.3, 45, .98, -3.4]` it can have all valid numeric values.
### Bar chart
A bar chart offers the capability to graphically depict bars.
#### Example
1. `bar [2.3, 45, .98, -3.4]` it can have all valid numeric values.
#### Simplest example
The only two things required are the chart name (`xychart-beta`) and one data set. So you will be able to draw a chart with a simple config like
xychart-beta
line [+1.3, .6, 2.4, -.34]
## Chart Configurations
| Parameter | Description | Default value |
| ------------------------ | ---------------------------------------------- | :-----------: |
| width | Width of the chart | 700 |
| height | Height of the chart | 500 |
| titlePadding | Top and Bottom padding of the title | 10 |
| titleFontSize | Title font size | 20 |
| showTitle | Title to be shown or not | true |
| xAxis | xAxis configuration | AxisConfig |
| yAxis | yAxis configuration | AxisConfig |
| chartOrientation | 'vertical' or 'horizontal' | 'vertical' |
| plotReservedSpacePercent | Minimum space plots will take inside the chart | 50 |
### AxisConfig
| Parameter | Description | Default value |
| ------------- | ------------------------------------ | :-----------: |
| showLabel | Show axis labels or tick values | true |
| labelFontSize | Font size of the label to be drawn | 14 |
| labelPadding | Top and Bottom padding of the label | 5 |
| showTitle | Axis title to be shown or not | true |
| titleFontSize | Axis title font size | 16 |
| titlePadding | Top and Bottom padding of Axis title | 5 |
| showTick | Tick to be shown or not | true |
| tickLength | How long the tick will be | 5 |
| tickWidth | How width the tick will be | 2 |
| showAxisLine | Axis line to be shown or not | true |
| axisLineWidth | Thickness of the axis line | 2 |
## Chart Theme Variables
> **Note**
> Themes for xychart resides inside xychart attribute so to set the variables use this syntax
> %%{init: { "themeVariables": {"xyChart": {"titleColor": "#ff0000"} } }}%%
| Parameter | Description |
| ---------------- | --------------------------------------------------------- |
| backgroundColor | Background color of the whole chart |
| titleColor | Color of the Title text |
| xAxisLableColor | Color of the x-axis labels |
| xAxisTitleColor | Color of the x-axis title |
| xAxisTickColor | Color of the x-axis tick |
| xAxisLineColor | Color of the x-axis line |
| yAxisLableColor | Color of the y-axis labels |
| yAxisTitleColor | Color of the y-axis title |
| yAxisTickColor | Color of the y-axis tick |
| yAxisLineColor | Color of the y-axis line |
| plotColorPalette | String of colors separated by comma e.g. "#f3456, #43445" |
## Example on config and theme
```mermaid-example
---
config:
xyChart:
width: 900
height: 600
themeVariables:
xyChart:
titleColor: "#ff0000"
---
xychart-beta
title "Sales Revenue"
x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
```
```mermaid
---
config:
xyChart:
width: 900
height: 600
themeVariables:
xyChart:
titleColor: "#ff0000"
---
xychart-beta
title "Sales Revenue"
x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
```

View File

@ -4,7 +4,7 @@
"version": "10.2.4", "version": "10.2.4",
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.", "description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
"type": "module", "type": "module",
"packageManager": "pnpm@8.7.5", "packageManager": "pnpm@8.9.2",
"keywords": [ "keywords": [
"diagram", "diagram",
"markdown", "markdown",
@ -77,8 +77,8 @@
"@types/node": "^18.16.0", "@types/node": "^18.16.0",
"@types/prettier": "^2.7.2", "@types/prettier": "^2.7.2",
"@types/rollup-plugin-visualizer": "^4.2.1", "@types/rollup-plugin-visualizer": "^4.2.1",
"@typescript-eslint/eslint-plugin": "^5.59.0", "@typescript-eslint/eslint-plugin": "^6.7.2",
"@typescript-eslint/parser": "^5.59.0", "@typescript-eslint/parser": "^6.7.2",
"@vitest/coverage-v8": "^0.34.0", "@vitest/coverage-v8": "^0.34.0",
"@vitest/spy": "^0.34.0", "@vitest/spy": "^0.34.0",
"@vitest/ui": "^0.34.0", "@vitest/ui": "^0.34.0",
@ -88,7 +88,7 @@
"cypress": "^12.10.0", "cypress": "^12.10.0",
"cypress-image-snapshot": "^4.0.1", "cypress-image-snapshot": "^4.0.1",
"esbuild": "^0.19.0", "esbuild": "^0.19.0",
"eslint": "^8.39.0", "eslint": "^8.47.0",
"eslint-config-prettier": "^8.8.0", "eslint-config-prettier": "^8.8.0",
"eslint-plugin-cypress": "^2.13.2", "eslint-plugin-cypress": "^2.13.2",
"eslint-plugin-html": "^7.1.0", "eslint-plugin-html": "^7.1.0",
@ -123,7 +123,7 @@
"vitest": "^0.34.0" "vitest": "^0.34.0"
}, },
"volta": { "volta": {
"node": "18.17.1" "node": "18.18.2"
}, },
"nyc": { "nyc": {
"report-dir": "coverage/cypress" "report-dir": "coverage/cypress"

View File

@ -1,6 +1,6 @@
{ {
"name": "mermaid", "name": "mermaid",
"version": "10.5.1", "version": "10.6.0",
"description": "Markdown-ish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.", "description": "Markdown-ish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
"type": "module", "type": "module",
"module": "./dist/mermaid.core.mjs", "module": "./dist/mermaid.core.mjs",

View File

@ -47,6 +47,7 @@ const MERMAID_CONFIG_DIAGRAM_KEYS = [
'er', 'er',
'pie', 'pie',
'quadrantChart', 'quadrantChart',
'xyChart',
'requirement', 'requirement',
'mindmap', 'mindmap',
'timeline', 'timeline',

View File

@ -150,6 +150,7 @@ export interface MermaidConfig {
er?: ErDiagramConfig; er?: ErDiagramConfig;
pie?: PieDiagramConfig; pie?: PieDiagramConfig;
quadrantChart?: QuadrantChartConfig; quadrantChart?: QuadrantChartConfig;
xyChart?: XYChartConfig;
requirement?: RequirementDiagramConfig; requirement?: RequirementDiagramConfig;
mindmap?: MindmapDiagramConfig; mindmap?: MindmapDiagramConfig;
gitGraph?: GitGraphDiagramConfig; gitGraph?: GitGraphDiagramConfig;
@ -703,6 +704,194 @@ export interface QuadrantChartConfig extends BaseDiagramConfig {
*/ */
quadrantExternalBorderStrokeWidth?: number; quadrantExternalBorderStrokeWidth?: number;
} }
/**
* This object contains configuration for XYChart axis config
*
* This interface was referenced by `MermaidConfig`'s JSON-Schema
* via the `definition` "XYChartAxisConfig".
*/
export interface XYChartAxisConfig {
/**
* Should show the axis labels (tick text)
*/
showLabel?: boolean;
/**
* font size of the axis labels (tick text)
*/
labelFontSize?: number;
/**
* top and bottom space from axis label (tick text)
*/
labelPadding?: number;
/**
* Should show the axis title
*/
showTitle?: boolean;
/**
* font size of the axis title
*/
titleFontSize?: number;
/**
* top and bottom space from axis title
*/
titlePadding?: number;
/**
* Should show the axis tick lines
*/
showTick?: boolean;
/**
* length of the axis tick lines
*/
tickLength?: number;
/**
* width of the axis tick lines
*/
tickWidth?: number;
/**
* Show line across the axis
*/
showAxisLine?: boolean;
/**
* Width of the axis line
*/
axisLineWidth?: number;
}
/**
* This object contains configuration specific to XYCharts
*
* This interface was referenced by `MermaidConfig`'s JSON-Schema
* via the `definition` "XYChartConfig".
*/
export interface XYChartConfig extends BaseDiagramConfig {
/**
* width of the chart
*/
width?: number;
/**
* height of the chart
*/
height?: number;
/**
* Font size of the chart title
*/
titleFontSize?: number;
/**
* Top and bottom space from the chart title
*/
titlePadding?: number;
/**
* Should show the chart title
*/
showTitle?: boolean;
xAxis?: XYChartAxisConfig1;
yAxis?: XYChartAxisConfig2;
/**
* How to plot will be drawn horizontal or vertical
*/
chartOrientation?: 'vertical' | 'horizontal';
/**
* Minimum percent of space plots of the chart will take
*/
plotReservedSpacePercent?: number;
}
/**
* This object contains configuration for XYChart axis config
*/
export interface XYChartAxisConfig1 {
/**
* Should show the axis labels (tick text)
*/
showLabel?: boolean;
/**
* font size of the axis labels (tick text)
*/
labelFontSize?: number;
/**
* top and bottom space from axis label (tick text)
*/
labelPadding?: number;
/**
* Should show the axis title
*/
showTitle?: boolean;
/**
* font size of the axis title
*/
titleFontSize?: number;
/**
* top and bottom space from axis title
*/
titlePadding?: number;
/**
* Should show the axis tick lines
*/
showTick?: boolean;
/**
* length of the axis tick lines
*/
tickLength?: number;
/**
* width of the axis tick lines
*/
tickWidth?: number;
/**
* Show line across the axis
*/
showAxisLine?: boolean;
/**
* Width of the axis line
*/
axisLineWidth?: number;
}
/**
* This object contains configuration for XYChart axis config
*/
export interface XYChartAxisConfig2 {
/**
* Should show the axis labels (tick text)
*/
showLabel?: boolean;
/**
* font size of the axis labels (tick text)
*/
labelFontSize?: number;
/**
* top and bottom space from axis label (tick text)
*/
labelPadding?: number;
/**
* Should show the axis title
*/
showTitle?: boolean;
/**
* font size of the axis title
*/
titleFontSize?: number;
/**
* top and bottom space from axis title
*/
titlePadding?: number;
/**
* Should show the axis tick lines
*/
showTick?: boolean;
/**
* length of the axis tick lines
*/
tickLength?: number;
/**
* width of the axis tick lines
*/
tickWidth?: number;
/**
* Show line across the axis
*/
showAxisLine?: boolean;
/**
* Width of the axis line
*/
axisLineWidth?: number;
}
/** /**
* The object containing configurations specific for entity relationship diagrams * The object containing configurations specific for entity relationship diagrams
* *

View File

@ -3,7 +3,7 @@ import { log } from '../logger.js';
import createLabel from './createLabel.js'; import createLabel from './createLabel.js';
import { createText } from '../rendering-util/createText.js'; import { createText } from '../rendering-util/createText.js';
import { select } from 'd3'; import { select } from 'd3';
import { getConfig } from '../config.js'; import { getConfig } from '../diagram-api/diagramAPI.js';
import { evaluate } from '../diagrams/common/common.js'; import { evaluate } from '../diagrams/common/common.js';
const rect = (parent, node) => { const rect = (parent, node) => {

View File

@ -1,6 +1,6 @@
import { select } from 'd3'; import { select } from 'd3';
import { log } from '../logger.js'; import { log } from '../logger.js';
import { getConfig } from '../config.js'; import { getConfig } from '../diagram-api/diagramAPI.js';
import { evaluate } from '../diagrams/common/common.js'; import { evaluate } from '../diagrams/common/common.js';
import { decodeEntities } from '../mermaidAPI.js'; import { decodeEntities } from '../mermaidAPI.js';

View File

@ -2,7 +2,7 @@ import { log } from '../logger.js';
import createLabel from './createLabel.js'; import createLabel from './createLabel.js';
import { createText } from '../rendering-util/createText.js'; import { createText } from '../rendering-util/createText.js';
import { line, curveBasis, select } from 'd3'; import { line, curveBasis, select } from 'd3';
import { getConfig } from '../config.js'; import { getConfig } from '../diagram-api/diagramAPI.js';
import utils from '../utils.js'; import utils from '../utils.js';
import { evaluate } from '../diagrams/common/common.js'; import { evaluate } from '../diagrams/common/common.js';
import { getLineFunctionsWithOffset } from '../utils/lineWithOffset.js'; import { getLineFunctionsWithOffset } from '../utils/lineWithOffset.js';

View File

@ -231,12 +231,12 @@ export const adjustClustersAndEdges = (graph, depth) => {
if (children.length > 0) { if (children.length > 0) {
log.debug('Cluster identified', id, descendants); log.debug('Cluster identified', id, descendants);
edges.forEach((edge) => { edges.forEach((edge) => {
// log.debug('Edge, decendants: ', edge, decendants[id]); // log.debug('Edge, descendants: ', edge, descendants[id]);
// Check if any edge leaves the cluster (not the actual cluster, that's a link from the box) // Check if any edge leaves the cluster (not the actual cluster, that's a link from the box)
if (edge.v !== id && edge.w !== id) { if (edge.v !== id && edge.w !== id) {
// Any edge where either the one of the nodes is descending to the cluster but not the other // Any edge where either the one of the nodes is descending to the cluster but not the other
// if (decendants[id].indexOf(edge.v) < 0 && decendants[id].indexOf(edge.w) < 0) { // if (descendants[id].indexOf(edge.v) < 0 && descendants[id].indexOf(edge.w) < 0) {
const d1 = isDescendant(edge.v, id); const d1 = isDescendant(edge.v, id);
const d2 = isDescendant(edge.w, id); const d2 = isDescendant(edge.w, id);

View File

@ -419,7 +419,7 @@ describe('extractDescendants', function () {
return {}; return {};
}); });
}); });
it('Simple case of one level decendants GLB9', function () { it('Simple case of one level descendants GLB9', function () {
/* /*
subgraph A subgraph A
a a

View File

@ -1,7 +1,7 @@
import { select } from 'd3'; import { select } from 'd3';
import { log } from '../logger.js'; import { log } from '../logger.js';
import { labelHelper, updateNodeBounds, insertPolygonShape } from './shapes/util.js'; import { labelHelper, updateNodeBounds, insertPolygonShape } from './shapes/util.js';
import { getConfig } from '../config.js'; import { getConfig } from '../diagram-api/diagramAPI.js';
import intersect from './intersect/index.js'; import intersect from './intersect/index.js';
import createLabel from './createLabel.js'; import createLabel from './createLabel.js';
import note from './shapes/note.js'; import note from './shapes/note.js';

View File

@ -1,6 +1,6 @@
import { updateNodeBounds, labelHelper } from './util.js'; import { updateNodeBounds, labelHelper } from './util.js';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import { getConfig } from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import intersect from '../intersect/index.js'; import intersect from '../intersect/index.js';
const note = async (parent, node) => { const note = async (parent, node) => {

View File

@ -1,6 +1,6 @@
import createLabel from '../createLabel.js'; import createLabel from '../createLabel.js';
import { createText } from '../../rendering-util/createText.js'; import { createText } from '../../rendering-util/createText.js';
import { getConfig } from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { decodeEntities } from '../../mermaidAPI.js'; import { decodeEntities } from '../../mermaidAPI.js';
import { select } from 'd3'; import { select } from 'd3';
import { evaluate, sanitizeText } from '../../diagrams/common/common.js'; import { evaluate, sanitizeText } from '../../diagrams/common/common.js';

View File

@ -236,6 +236,10 @@ const config: RequiredDeep<MermaidConfig> = {
...defaultConfigJson.pie, ...defaultConfigJson.pie,
useWidth: 984, useWidth: 984,
}, },
xyChart: {
...defaultConfigJson.xyChart,
useWidth: undefined,
},
requirement: { requirement: {
...defaultConfigJson.requirement, ...defaultConfigJson.requirement,
useWidth: undefined, useWidth: undefined,

View File

@ -7,6 +7,7 @@ import gantt from '../diagrams/gantt/ganttDetector.js';
import { info } from '../diagrams/info/infoDetector.js'; import { info } from '../diagrams/info/infoDetector.js';
import { pie } from '../diagrams/pie/pieDetector.js'; import { pie } from '../diagrams/pie/pieDetector.js';
import quadrantChart from '../diagrams/quadrant-chart/quadrantDetector.js'; import quadrantChart from '../diagrams/quadrant-chart/quadrantDetector.js';
import xychart from '../diagrams/xychart/xychartDetector.js';
import requirement from '../diagrams/requirement/requirementDetector.js'; import requirement from '../diagrams/requirement/requirementDetector.js';
import sequence from '../diagrams/sequence/sequenceDetector.js'; import sequence from '../diagrams/sequence/sequenceDetector.js';
import classDiagram from '../diagrams/class/classDetector.js'; import classDiagram from '../diagrams/class/classDetector.js';
@ -85,6 +86,7 @@ export const addDiagrams = () => {
state, state,
journey, journey,
quadrantChart, quadrantChart,
sankey sankey,
xychart
); );
}; };

View File

@ -1,6 +1,11 @@
import { addDetector } from './detectType.js'; import { addDetector } from './detectType.js';
import { log as _log, setLogLevel as _setLogLevel } from '../logger.js'; import { log as _log, setLogLevel as _setLogLevel } from '../logger.js';
import { getConfig as _getConfig } from '../config.js'; import {
getConfig as _getConfig,
setConfig as _setConfig,
defaultConfig as _defaultConfig,
setSiteConfig as _setSiteConfig,
} from '../config.js';
import { sanitizeText as _sanitizeText } from '../diagrams/common/common.js'; import { sanitizeText as _sanitizeText } from '../diagrams/common/common.js';
import { setupGraphViewbox as _setupGraphViewbox } from '../setupGraphViewbox.js'; import { setupGraphViewbox as _setupGraphViewbox } from '../setupGraphViewbox.js';
import { addStylesForDiagram } from '../styles.js'; import { addStylesForDiagram } from '../styles.js';
@ -15,6 +20,9 @@ import * as _commonDb from '../diagrams/common/commonDb.js';
export const log = _log; export const log = _log;
export const setLogLevel = _setLogLevel; export const setLogLevel = _setLogLevel;
export const getConfig = _getConfig; export const getConfig = _getConfig;
export const setConfig = _setConfig;
export const defaultConfig = _defaultConfig;
export const setSiteConfig = _setSiteConfig;
export const sanitizeText = (text: string) => _sanitizeText(text, getConfig()); export const sanitizeText = (text: string) => _sanitizeText(text, getConfig());
export const setupGraphViewbox = _setupGraphViewbox; export const setupGraphViewbox = _setupGraphViewbox;
export const getCommonDb = () => { export const getCommonDb = () => {

View File

@ -1,4 +1,4 @@
import * as configApi from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { sanitizeText } from '../common/common.js'; import { sanitizeText } from '../common/common.js';
import { import {
setAccTitle, setAccTitle,
@ -33,7 +33,7 @@ export const getC4Type = function () {
}; };
export const setC4Type = function (c4TypeParam) { export const setC4Type = function (c4TypeParam) {
let sanitizedText = sanitizeText(c4TypeParam, configApi.getConfig()); let sanitizedText = sanitizeText(c4TypeParam, getConfig());
c4Type = sanitizedText; c4Type = sanitizedText;
}; };
@ -783,7 +783,7 @@ export const PLACEMENT = {
}; };
export const setTitle = function (txt) { export const setTitle = function (txt) {
let sanitizedText = sanitizeText(txt, configApi.getConfig()); let sanitizedText = sanitizeText(txt, getConfig());
title = sanitizedText; title = sanitizedText;
}; };
@ -816,7 +816,7 @@ export default {
getAccTitle, getAccTitle,
getAccDescription, getAccDescription,
setAccDescription, setAccDescription,
getConfig: () => configApi.getConfig().c4, getConfig: () => getConfig().c4,
clear, clear,
LINETYPE, LINETYPE,
ARROWTYPE, ARROWTYPE,

View File

@ -4,7 +4,7 @@ import { log } from '../../logger.js';
import { parser } from './parser/c4Diagram.jison'; import { parser } from './parser/c4Diagram.jison';
import common from '../common/common.js'; import common from '../common/common.js';
import c4Db from './c4Db.js'; import c4Db from './c4Db.js';
import * as configApi from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import assignWithDepth from '../../assignWithDepth.js'; import assignWithDepth from '../../assignWithDepth.js';
import { wrapLabel, calculateTextWidth, calculateTextHeight } from '../../utils.js'; import { wrapLabel, calculateTextWidth, calculateTextHeight } from '../../utils.js';
import { configureSvgSize } from '../../setupGraphViewbox.js'; import { configureSvgSize } from '../../setupGraphViewbox.js';
@ -580,8 +580,8 @@ function drawInsideBoundary(
* @param diagObj * @param diagObj
*/ */
export const draw = function (_text, id, _version, diagObj) { export const draw = function (_text, id, _version, diagObj) {
conf = configApi.getConfig().c4; conf = getConfig().c4;
const securityLevel = configApi.getConfig().securityLevel; const securityLevel = getConfig().securityLevel;
// Handle root and Document for when rendering in sandbox mode // Handle root and Document for when rendering in sandbox mode
let sandboxElement; let sandboxElement;
if (securityLevel === 'sandbox') { if (securityLevel === 'sandbox') {

View File

@ -1,7 +1,7 @@
import type { Selection } from 'd3'; import type { Selection } from 'd3';
import { select } from 'd3'; import { select } from 'd3';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import * as configApi from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import common from '../common/common.js'; import common from '../common/common.js';
import utils from '../../utils.js'; import utils from '../../utils.js';
import { import {
@ -34,10 +34,10 @@ let namespaceCounter = 0;
let functions: any[] = []; let functions: any[] = [];
const sanitizeText = (txt: string) => common.sanitizeText(txt, configApi.getConfig()); const sanitizeText = (txt: string) => common.sanitizeText(txt, getConfig());
const splitClassNameAndType = function (_id: string) { const splitClassNameAndType = function (_id: string) {
const id = common.sanitizeText(_id, configApi.getConfig()); const id = common.sanitizeText(_id, getConfig());
let genericType = ''; let genericType = '';
let className = id; let className = id;
@ -51,7 +51,7 @@ const splitClassNameAndType = function (_id: string) {
}; };
export const setClassLabel = function (_id: string, label: string) { export const setClassLabel = function (_id: string, label: string) {
const id = common.sanitizeText(_id, configApi.getConfig()); const id = common.sanitizeText(_id, getConfig());
if (label) { if (label) {
label = sanitizeText(label); label = sanitizeText(label);
} }
@ -67,14 +67,14 @@ export const setClassLabel = function (_id: string, label: string) {
* @public * @public
*/ */
export const addClass = function (_id: string) { export const addClass = function (_id: string) {
const id = common.sanitizeText(_id, configApi.getConfig()); const id = common.sanitizeText(_id, getConfig());
const { className, type } = splitClassNameAndType(id); const { className, type } = splitClassNameAndType(id);
// Only add class if not exists // Only add class if not exists
if (Object.hasOwn(classes, className)) { if (Object.hasOwn(classes, className)) {
return; return;
} }
// alert('Adding class: ' + className); // alert('Adding class: ' + className);
const name = common.sanitizeText(className, configApi.getConfig()); const name = common.sanitizeText(className, getConfig());
// alert('Adding class after: ' + name); // alert('Adding class after: ' + name);
classes[name] = { classes[name] = {
id: name, id: name,
@ -97,7 +97,7 @@ export const addClass = function (_id: string) {
* @public * @public
*/ */
export const lookUpDomId = function (_id: string): string { export const lookUpDomId = function (_id: string): string {
const id = common.sanitizeText(_id, configApi.getConfig()); const id = common.sanitizeText(_id, getConfig());
if (id in classes) { if (id in classes) {
return classes[id].domId; return classes[id].domId;
} }
@ -139,15 +139,9 @@ export const addRelation = function (relation: ClassRelation) {
relation.id1 = splitClassNameAndType(relation.id1).className; relation.id1 = splitClassNameAndType(relation.id1).className;
relation.id2 = splitClassNameAndType(relation.id2).className; relation.id2 = splitClassNameAndType(relation.id2).className;
relation.relationTitle1 = common.sanitizeText( relation.relationTitle1 = common.sanitizeText(relation.relationTitle1.trim(), getConfig());
relation.relationTitle1.trim(),
configApi.getConfig()
);
relation.relationTitle2 = common.sanitizeText( relation.relationTitle2 = common.sanitizeText(relation.relationTitle2.trim(), getConfig());
relation.relationTitle2.trim(),
configApi.getConfig()
);
relations.push(relation); relations.push(relation);
}; };
@ -267,7 +261,7 @@ export const getTooltip = function (id: string, namespace?: string) {
* @param target - Target of the link, _blank by default as originally defined in the svgDraw.js file * @param target - Target of the link, _blank by default as originally defined in the svgDraw.js file
*/ */
export const setLink = function (ids: string, linkStr: string, target: string) { export const setLink = function (ids: string, linkStr: string, target: string) {
const config = configApi.getConfig(); const config = getConfig();
ids.split(',').forEach(function (_id) { ids.split(',').forEach(function (_id) {
let id = _id; let id = _id;
if (_id[0].match(/\d/)) { if (_id[0].match(/\d/)) {
@ -303,8 +297,8 @@ export const setClickEvent = function (ids: string, functionName: string, functi
}; };
const setClickFunc = function (_domId: string, functionName: string, functionArgs: string) { const setClickFunc = function (_domId: string, functionName: string, functionArgs: string) {
const domId = common.sanitizeText(_domId, configApi.getConfig()); const domId = common.sanitizeText(_domId, getConfig());
const config = configApi.getConfig(); const config = getConfig();
if (config.securityLevel !== 'loose') { if (config.securityLevel !== 'loose') {
return; return;
} }
@ -465,7 +459,7 @@ export default {
getAccTitle, getAccTitle,
getAccDescription, getAccDescription,
setAccDescription, setAccDescription,
getConfig: () => configApi.getConfig().class, getConfig: () => getConfig().class,
addClass, addClass,
bindFunctions, bindFunctions,
clear, clear,

View File

@ -2,7 +2,7 @@
import { select, curveLinear } from 'd3'; import { select, curveLinear } from 'd3';
import * as graphlib from 'dagre-d3-es/src/graphlib/index.js'; import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import { getConfig } from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { render } from '../../dagre-wrapper/index.js'; import { render } from '../../dagre-wrapper/index.js';
import utils from '../../utils.js'; import utils from '../../utils.js';
import { interpolateToCurve, getStylesFromArray } from '../../utils.js'; import { interpolateToCurve, getStylesFromArray } from '../../utils.js';

View File

@ -4,7 +4,7 @@ import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import svgDraw from './svgDraw.js'; import svgDraw from './svgDraw.js';
import { configureSvgSize } from '../../setupGraphViewbox.js'; import { configureSvgSize } from '../../setupGraphViewbox.js';
import { getConfig } from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
let idCache = {}; let idCache = {};
const padding = 20; const padding = 20;

View File

@ -1,4 +1,4 @@
import { getConfig } from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { parseGenericTypes, sanitizeText } from '../common/common.js'; import { parseGenericTypes, sanitizeText } from '../common/common.js';
export interface ClassNode { export interface ClassNode {

View File

@ -1,7 +1,6 @@
const getStyles = (options) => const getStyles = (options) =>
`g.classGroup text { `g.classGroup text {
fill: ${options.nodeBorder}; fill: ${options.nodeBorder || options.classText};
fill: ${options.classText};
stroke: none; stroke: none;
font-family: ${options.fontFamily}; font-family: ${options.fontFamily};
font-size: 10px; font-size: 10px;

View File

@ -1,5 +1,5 @@
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import * as configApi from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { import {
setAccTitle, setAccTitle,
@ -83,7 +83,7 @@ const clear = function () {
export default { export default {
Cardinality, Cardinality,
Identification, Identification,
getConfig: () => configApi.getConfig().er, getConfig: () => getConfig().er,
addEntity, addEntity,
addAttributes, addAttributes,
getEntities, getEntities,

View File

@ -1,7 +1,7 @@
import * as graphlib from 'dagre-d3-es/src/graphlib/index.js'; import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
import { line, curveBasis, select } from 'd3'; import { line, curveBasis, select } from 'd3';
import { layout as dagreLayout } from 'dagre-d3-es/src/dagre/index.js'; import { layout as dagreLayout } from 'dagre-d3-es/src/dagre/index.js';
import { getConfig } from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import utils from '../../utils.js'; import utils from '../../utils.js';
import erMarkers from './erMarkers.js'; import erMarkers from './erMarkers.js';
@ -202,7 +202,7 @@ const drawAttributes = (groupNode, entityTextNode, attributes) => {
let attribStyle = 'attributeBoxOdd'; // We will flip the style on alternate rows to achieve a banded effect let attribStyle = 'attributeBoxOdd'; // We will flip the style on alternate rows to achieve a banded effect
attributeNodes.forEach((attributeNode) => { attributeNodes.forEach((attributeNode) => {
// Calculate the alignment y co-ordinate for the type/name of the attribute // Calculate the alignment y coordinate for the type/name of the attribute
const alignY = heightOffset + heightPadding + attributeNode.height / 2; const alignY = heightOffset + heightPadding + attributeNode.height / 2;
// Position the type attribute // Position the type attribute
@ -579,8 +579,8 @@ export const draw = function (text, id, _version, diagObj) {
// 2. Make sure they are all added to the graph // 2. Make sure they are all added to the graph
// 3. Add all the edges (relationships) to the graph as well // 3. Add all the edges (relationships) to the graph as well
// 4. Let dagre do its magic to lay out the graph. This assigns: // 4. Let dagre do its magic to lay out the graph. This assigns:
// - the centre co-ordinates for each node, bearing in mind the dimensions and edge relationships // - the centre coordinates for each node, bearing in mind the dimensions and edge relationships
// - the path co-ordinates for each edge // - the path coordinates for each edge
// But it has no impact on the svg child nodes - the diagram remains with every entity rooted at 0,0 // But it has no impact on the svg child nodes - the diagram remains with every entity rooted at 0,0
// 5. Now assign a transform to each entity in the svg node so that it gets drawn in the correct place, as determined by // 5. Now assign a transform to each entity in the svg node so that it gets drawn in the correct place, as determined by
// its centre point, which is obtained from the graph, and it's width and height // its centre point, which is obtained from the graph, and it's width and height

View File

@ -92,7 +92,7 @@ describe('when parsing ER diagram it...', function () {
}); });
}); });
it('cannot contain % because it interfers with parsing comments', function () { it('cannot contain % because it interferes with parsing comments', function () {
expect(() => { expect(() => {
erDiagram.parser.parse(`erDiagram\n "Blo%rf"\n`); erDiagram.parser.parse(`erDiagram\n "Blo%rf"\n`);
const entities = erDb.getEntities(); const entities = erDb.getEntities();

View File

@ -561,7 +561,7 @@ export const addEdges = function (edges, diagObj, graph, svg) {
}; };
// TODO: break out and share with dagre wrapper. The current code in dagre wrapper also adds // 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 // adds the line to the graph, but we don't need that here. This is why we can't use the dagre
// wrapper directly for this // wrapper directly for this
/** /**
* Add the markers to the edge depending on the type of arrow is * Add the markers to the edge depending on the type of arrow is

View File

@ -1,6 +1,6 @@
import { select } from 'd3'; import { select } from 'd3';
import utils from '../../utils.js'; import utils from '../../utils.js';
import * as configApi from '../../config.js'; import { getConfig, defaultConfig } from '../../diagram-api/diagramAPI.js';
import common from '../common/common.js'; import common from '../common/common.js';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import { import {
@ -12,10 +12,11 @@ import {
setDiagramTitle, setDiagramTitle,
getDiagramTitle, getDiagramTitle,
} from '../common/commonDb.js'; } from '../common/commonDb.js';
import errorDiagram from '../error/errorDiagram.js';
const MERMAID_DOM_ID_PREFIX = 'flowchart-'; const MERMAID_DOM_ID_PREFIX = 'flowchart-';
let vertexCounter = 0; let vertexCounter = 0;
let config = configApi.getConfig(); let config = getConfig();
let vertices = {}; let vertices = {};
let edges = []; let edges = [];
let classes = {}; let classes = {};
@ -84,7 +85,7 @@ export const addVertex = function (_id, textObj, type, style, classes, dir, prop
} }
vertexCounter++; vertexCounter++;
if (textObj !== undefined) { if (textObj !== undefined) {
config = configApi.getConfig(); config = getConfig();
txt = sanitizeText(textObj.text.trim()); txt = sanitizeText(textObj.text.trim());
vertices[id].labelType = textObj.type; vertices[id].labelType = textObj.type;
// strip quotes if string starts and ends with a quote // strip quotes if string starts and ends with a quote
@ -156,7 +157,15 @@ export const addSingleLink = function (_start, _end, type) {
edge.stroke = type.stroke; edge.stroke = type.stroke;
edge.length = type.length; edge.length = type.length;
} }
edges.push(edge); if (edge?.length > 10) {
edge.length = 10;
}
if (edges.length < 280) {
log.info('abc78 pushing edge...');
edges.push(edge);
} else {
throw new Error('Too many edges');
}
}; };
export const addLink = function (_start, _end, type) { export const addLink = function (_start, _end, type) {
log.info('addLink (abc78)', _start, _end, type); log.info('addLink (abc78)', _start, _end, type);
@ -277,7 +286,7 @@ const setTooltip = function (ids, tooltip) {
const setClickFun = function (id, functionName, functionArgs) { const setClickFun = function (id, functionName, functionArgs) {
let domId = lookUpDomId(id); let domId = lookUpDomId(id);
// if (_id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id; // if (_id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id;
if (configApi.getConfig().securityLevel !== 'loose') { if (getConfig().securityLevel !== 'loose') {
return; return;
} }
if (functionName === undefined) { if (functionName === undefined) {
@ -766,7 +775,7 @@ export const lex = {
firstGraph, firstGraph,
}; };
export default { export default {
defaultConfig: () => configApi.defaultConfig.flowchart, defaultConfig: () => defaultConfig.flowchart,
setAccTitle, setAccTitle,
getAccTitle, getAccTitle,
getAccDescription, getAccDescription,

View File

@ -4,7 +4,7 @@ import flowDb from './flowDb.js';
import flowRendererV2 from './flowRenderer-v2.js'; import flowRendererV2 from './flowRenderer-v2.js';
import flowStyles from './styles.js'; import flowStyles from './styles.js';
import type { MermaidConfig } from '../../config.type.js'; import type { MermaidConfig } from '../../config.type.js';
import { setConfig } from '../../config.js'; import { setConfig } from '../../diagram-api/diagramAPI.js';
export const diagram = { export const diagram = {
parser: flowParser, parser: flowParser,

View File

@ -1,6 +1,6 @@
import * as graphlib from 'dagre-d3-es/src/graphlib/index.js'; import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
import { select, curveLinear, selectAll } from 'd3'; import { select, curveLinear, selectAll } from 'd3';
import { getConfig } from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import utils from '../../utils.js'; import utils from '../../utils.js';
import { render } from '../../dagre-wrapper/index.js'; import { render } from '../../dagre-wrapper/index.js';
import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js'; import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js';

View File

@ -1,6 +1,6 @@
import * as graphlib from 'dagre-d3-es/src/graphlib/index.js'; import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
import { select, curveLinear, selectAll } from 'd3'; import { select, curveLinear, selectAll } from 'd3';
import { getConfig } from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { render as Render } from 'dagre-d3-es'; import { render as Render } from 'dagre-d3-es';
import { applyStyle } from 'dagre-d3-es/src/dagre-js/util.js'; import { applyStyle } from 'dagre-d3-es/src/dagre-js/util.js';
import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js'; import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js';

View File

@ -1,5 +1,5 @@
import { addVertices, addEdges } from './flowRenderer.js'; import { addVertices, addEdges } from './flowRenderer.js';
import { setConfig } from '../../config.js'; import { setConfig } from '../../diagram-api/diagramAPI.js';
setConfig({ setConfig({
flowchart: { flowchart: {

File diff suppressed because one or more lines are too long

View File

@ -4,7 +4,7 @@ import dayjsIsoWeek from 'dayjs/plugin/isoWeek.js';
import dayjsCustomParseFormat from 'dayjs/plugin/customParseFormat.js'; import dayjsCustomParseFormat from 'dayjs/plugin/customParseFormat.js';
import dayjsAdvancedFormat from 'dayjs/plugin/advancedFormat.js'; import dayjsAdvancedFormat from 'dayjs/plugin/advancedFormat.js';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import * as configApi from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import utils from '../../utils.js'; import utils from '../../utils.js';
import { import {
@ -603,7 +603,7 @@ const compileTasks = function () {
*/ */
export const setLink = function (ids, _linkStr) { export const setLink = function (ids, _linkStr) {
let linkStr = _linkStr; let linkStr = _linkStr;
if (configApi.getConfig().securityLevel !== 'loose') { if (getConfig().securityLevel !== 'loose') {
linkStr = sanitizeUrl(_linkStr); linkStr = sanitizeUrl(_linkStr);
} }
ids.split(',').forEach(function (id) { ids.split(',').forEach(function (id) {
@ -634,7 +634,7 @@ export const setClass = function (ids, className) {
}; };
const setClickFun = function (id, functionName, functionArgs) { const setClickFun = function (id, functionName, functionArgs) {
if (configApi.getConfig().securityLevel !== 'loose') { if (getConfig().securityLevel !== 'loose') {
return; return;
} }
if (functionName === undefined) { if (functionName === undefined) {
@ -725,7 +725,7 @@ export const bindFunctions = function (element) {
}; };
export default { export default {
getConfig: () => configApi.getConfig().gantt, getConfig: () => getConfig().gantt,
clear, clear,
setDateFormat, setDateFormat,
getDateFormat, getDateFormat,

View File

@ -25,7 +25,7 @@ import {
timeMonth, timeMonth,
} from 'd3'; } from 'd3';
import common from '../common/common.js'; import common from '../common/common.js';
import { getConfig } from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { configureSvgSize } from '../../setupGraphViewbox.js'; import { configureSvgSize } from '../../setupGraphViewbox.js';
export const setConf = function () { export const setConf = function () {

View File

@ -1,7 +1,6 @@
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import { random } from '../../utils.js'; import { random } from '../../utils.js';
import * as configApi from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { getConfig } from '../../config.js';
import common from '../common/common.js'; import common from '../common/common.js';
import { import {
setAccTitle, setAccTitle,
@ -106,9 +105,9 @@ export const getOptions = function () {
export const commit = function (msg, id, type, tag) { export const commit = function (msg, id, type, tag) {
log.debug('Entering commit:', msg, id, type, tag); log.debug('Entering commit:', msg, id, type, tag);
id = common.sanitizeText(id, configApi.getConfig()); id = common.sanitizeText(id, getConfig());
msg = common.sanitizeText(msg, configApi.getConfig()); msg = common.sanitizeText(msg, getConfig());
tag = common.sanitizeText(tag, configApi.getConfig()); tag = common.sanitizeText(tag, getConfig());
const commit = { const commit = {
id: id ? id : seq + '-' + getId(), id: id ? id : seq + '-' + getId(),
message: msg, message: msg,
@ -125,7 +124,7 @@ export const commit = function (msg, id, type, tag) {
}; };
export const branch = function (name, order) { export const branch = function (name, order) {
name = common.sanitizeText(name, configApi.getConfig()); name = common.sanitizeText(name, getConfig());
if (branches[name] === undefined) { if (branches[name] === undefined) {
branches[name] = head != null ? head.id : null; branches[name] = head != null ? head.id : null;
branchesConfig[name] = { name, order: order ? parseInt(order, 10) : null }; branchesConfig[name] = { name, order: order ? parseInt(order, 10) : null };
@ -149,8 +148,8 @@ export const branch = function (name, order) {
}; };
export const merge = function (otherBranch, custom_id, override_type, custom_tag) { export const merge = function (otherBranch, custom_id, override_type, custom_tag) {
otherBranch = common.sanitizeText(otherBranch, configApi.getConfig()); otherBranch = common.sanitizeText(otherBranch, getConfig());
custom_id = common.sanitizeText(custom_id, configApi.getConfig()); custom_id = common.sanitizeText(custom_id, getConfig());
const currentCommit = commits[branches[curBranch]]; const currentCommit = commits[branches[curBranch]];
const otherCommit = commits[branches[otherBranch]]; const otherCommit = commits[branches[otherBranch]];
@ -258,9 +257,9 @@ export const merge = function (otherBranch, custom_id, override_type, custom_tag
export const cherryPick = function (sourceId, targetId, tag) { export const cherryPick = function (sourceId, targetId, tag) {
log.debug('Entering cherryPick:', sourceId, targetId, tag); log.debug('Entering cherryPick:', sourceId, targetId, tag);
sourceId = common.sanitizeText(sourceId, configApi.getConfig()); sourceId = common.sanitizeText(sourceId, getConfig());
targetId = common.sanitizeText(targetId, configApi.getConfig()); targetId = common.sanitizeText(targetId, getConfig());
tag = common.sanitizeText(tag, configApi.getConfig()); tag = common.sanitizeText(tag, getConfig());
if (!sourceId || commits[sourceId] === undefined) { if (!sourceId || commits[sourceId] === undefined) {
let error = new Error( let error = new Error(
@ -338,7 +337,7 @@ export const cherryPick = function (sourceId, targetId, tag) {
} }
}; };
export const checkout = function (branch) { export const checkout = function (branch) {
branch = common.sanitizeText(branch, configApi.getConfig()); branch = common.sanitizeText(branch, getConfig());
if (branches[branch] === undefined) { if (branches[branch] === undefined) {
let error = new Error( let error = new Error(
'Trying to checkout branch which is not yet created. (Help try using "branch ' + branch + '")' 'Trying to checkout branch which is not yet created. (Help try using "branch ' + branch + '")'
@ -502,7 +501,7 @@ export const commitType = {
}; };
export default { export default {
getConfig: () => configApi.getConfig().gitGraph, getConfig: () => getConfig().gitGraph,
setDirection, setDirection,
setOptions, setOptions,
getOptions, getOptions,

View File

@ -6,7 +6,7 @@ describe('when parsing a gitGraph', function () {
parser.yy = gitGraphAst; parser.yy = gitGraphAst;
parser.yy.clear(); parser.yy.clear();
}); });
it('should handle a gitGraph commit with NO pararms, get auto-genrated reandom ID', function () { it('should handle a gitGraph commit with NO pararms, get auto-generated reandom ID', function () {
const str = `gitGraph: const str = `gitGraph:
commit commit
`; `;

View File

@ -1,4 +1,4 @@
import { getConfig } from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
export default (dir, _branches) => { export default (dir, _branches) => {
const config = getConfig().gitGraph; const config = getConfig().gitGraph;

View File

@ -129,7 +129,7 @@ root
expect(child.nodeId).toEqual('theId'); expect(child.nodeId).toEqual('theId');
expect(child.type).toEqual(mindmap.yy.nodeType.ROUNDED_RECT); expect(child.type).toEqual(mindmap.yy.nodeType.ROUNDED_RECT);
}); });
it('MMP-10 mutiple types (circle)', function () { it('MMP-10 multiple types (circle)', function () {
let str = `mindmap let str = `mindmap
root((the root)) root((the root))
`; `;
@ -141,7 +141,7 @@ root
expect(mm.type).toEqual(mindmap.yy.nodeType.CIRCLE); expect(mm.type).toEqual(mindmap.yy.nodeType.CIRCLE);
}); });
it('MMP-11 mutiple types (cloud)', function () { it('MMP-11 multiple types (cloud)', function () {
let str = `mindmap let str = `mindmap
root)the root( root)the root(
`; `;
@ -152,7 +152,7 @@ root
expect(mm.children.length).toEqual(0); expect(mm.children.length).toEqual(0);
expect(mm.type).toEqual(mindmap.yy.nodeType.CLOUD); expect(mm.type).toEqual(mindmap.yy.nodeType.CLOUD);
}); });
it('MMP-12 mutiple types (bang)', function () { it('MMP-12 multiple types (bang)', function () {
let str = `mindmap let str = `mindmap
root))the root(( root))the root((
`; `;
@ -164,7 +164,7 @@ root
expect(mm.type).toEqual(mindmap.yy.nodeType.BANG); expect(mm.type).toEqual(mindmap.yy.nodeType.BANG);
}); });
it('MMP-12-a mutiple types (hexagon)', function () { it('MMP-12-a multiple types (hexagon)', function () {
let str = `mindmap let str = `mindmap
root{{the root}} root{{the root}}
`; `;

View File

@ -1,4 +1,4 @@
import { getConfig } from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { sanitizeText as _sanitizeText } from '../../diagrams/common/common.js'; import { sanitizeText as _sanitizeText } from '../../diagrams/common/common.js';
import { log } from '../../logger.js'; import { log } from '../../logger.js';

View File

@ -1,7 +1,7 @@
/** Created by knut on 14-12-11. */ /** Created by knut on 14-12-11. */
import { select } from 'd3'; import { select } from 'd3';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import { getConfig } from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { setupGraphViewbox } from '../../setupGraphViewbox.js'; import { setupGraphViewbox } from '../../setupGraphViewbox.js';
import svgDraw from './svgDraw.js'; import svgDraw from './svgDraw.js';
import cytoscape from 'cytoscape/dist/cytoscape.umd.js'; import cytoscape from 'cytoscape/dist/cytoscape.umd.js';

View File

@ -1,7 +1,7 @@
// @ts-ignore: JISON doesn't support types // @ts-ignore: JISON doesn't support types
import { parser } from './parser/pie.jison'; import { parser } from './parser/pie.jison';
import { DEFAULT_PIE_DB, db } from './pieDb.js'; import { DEFAULT_PIE_DB, db } from './pieDb.js';
import { setConfig } from '../../config.js'; import { setConfig } from '../../diagram-api/diagramAPI.js';
setConfig({ setConfig({
securityLevel: 'strict', securityLevel: 'strict',

View File

@ -1,5 +1,5 @@
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import { getConfig as commonGetConfig } from '../../config.js'; import { getConfig as commonGetConfig } from '../../diagram-api/diagramAPI.js';
import { sanitizeText } from '../common/common.js'; import { sanitizeText } from '../common/common.js';
import { import {
setAccTitle, setAccTitle,

View File

@ -3,7 +3,7 @@ import { scaleOrdinal, pie as d3pie, arc } from 'd3';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import { configureSvgSize } from '../../setupGraphViewbox.js'; import { configureSvgSize } from '../../setupGraphViewbox.js';
import { getConfig } from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { cleanAndMerge, parseFontSize } from '../../utils.js'; import { cleanAndMerge, parseFontSize } from '../../utils.js';
import type { DrawDefinition, Group, SVG } from '../../diagram-api/types.js'; import type { DrawDefinition, Group, SVG } from '../../diagram-api/types.js';
import type { D3Sections, PieDB, Sections } from './pieTypes.js'; import type { D3Sections, PieDB, Sections } from './pieTypes.js';

View File

@ -1,4 +1,3 @@
// @ts-ignore: TODO Fix ts errors
import { scaleLinear } from 'd3'; import { scaleLinear } from 'd3';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import type { BaseDiagramConfig, QuadrantChartConfig } from '../../config.type.js'; import type { BaseDiagramConfig, QuadrantChartConfig } from '../../config.type.js';
@ -283,14 +282,17 @@ export class QuadrantBuilder {
quadrantTop, quadrantTop,
quadrantWidth, quadrantWidth,
} = quadrantSpace; } = quadrantSpace;
const drawAxisLabelInMiddle = this.data.points.length === 0;
const drawXAxisLabelsInMiddle = Boolean(this.data.xAxisRightText);
const drawYAxisLabelsInMiddle = Boolean(this.data.yAxisTopText);
const axisLabels: QuadrantTextType[] = []; const axisLabels: QuadrantTextType[] = [];
if (this.data.xAxisLeftText && showXAxis) { if (this.data.xAxisLeftText && showXAxis) {
axisLabels.push({ axisLabels.push({
text: this.data.xAxisLeftText, text: this.data.xAxisLeftText,
fill: this.themeConfig.quadrantXAxisTextFill, fill: this.themeConfig.quadrantXAxisTextFill,
x: quadrantLeft + (drawAxisLabelInMiddle ? quadrantHalfWidth / 2 : 0), x: quadrantLeft + (drawXAxisLabelsInMiddle ? quadrantHalfWidth / 2 : 0),
y: y:
xAxisPosition === 'top' xAxisPosition === 'top'
? this.config.xAxisLabelPadding + titleSpace.top ? this.config.xAxisLabelPadding + titleSpace.top
@ -299,7 +301,7 @@ export class QuadrantBuilder {
quadrantHeight + quadrantHeight +
this.config.quadrantPadding, this.config.quadrantPadding,
fontSize: this.config.xAxisLabelFontSize, fontSize: this.config.xAxisLabelFontSize,
verticalPos: drawAxisLabelInMiddle ? 'center' : 'left', verticalPos: drawXAxisLabelsInMiddle ? 'center' : 'left',
horizontalPos: 'top', horizontalPos: 'top',
rotation: 0, rotation: 0,
}); });
@ -308,7 +310,7 @@ export class QuadrantBuilder {
axisLabels.push({ axisLabels.push({
text: this.data.xAxisRightText, text: this.data.xAxisRightText,
fill: this.themeConfig.quadrantXAxisTextFill, fill: this.themeConfig.quadrantXAxisTextFill,
x: quadrantLeft + quadrantHalfWidth + (drawAxisLabelInMiddle ? quadrantHalfWidth / 2 : 0), x: quadrantLeft + quadrantHalfWidth + (drawXAxisLabelsInMiddle ? quadrantHalfWidth / 2 : 0),
y: y:
xAxisPosition === 'top' xAxisPosition === 'top'
? this.config.xAxisLabelPadding + titleSpace.top ? this.config.xAxisLabelPadding + titleSpace.top
@ -317,7 +319,7 @@ export class QuadrantBuilder {
quadrantHeight + quadrantHeight +
this.config.quadrantPadding, this.config.quadrantPadding,
fontSize: this.config.xAxisLabelFontSize, fontSize: this.config.xAxisLabelFontSize,
verticalPos: drawAxisLabelInMiddle ? 'center' : 'left', verticalPos: drawXAxisLabelsInMiddle ? 'center' : 'left',
horizontalPos: 'top', horizontalPos: 'top',
rotation: 0, rotation: 0,
}); });
@ -334,9 +336,9 @@ export class QuadrantBuilder {
quadrantLeft + quadrantLeft +
quadrantWidth + quadrantWidth +
this.config.quadrantPadding, this.config.quadrantPadding,
y: quadrantTop + quadrantHeight - (drawAxisLabelInMiddle ? quadrantHalfHeight / 2 : 0), y: quadrantTop + quadrantHeight - (drawYAxisLabelsInMiddle ? quadrantHalfHeight / 2 : 0),
fontSize: this.config.yAxisLabelFontSize, fontSize: this.config.yAxisLabelFontSize,
verticalPos: drawAxisLabelInMiddle ? 'center' : 'left', verticalPos: drawYAxisLabelsInMiddle ? 'center' : 'left',
horizontalPos: 'top', horizontalPos: 'top',
rotation: -90, rotation: -90,
}); });
@ -352,9 +354,10 @@ export class QuadrantBuilder {
quadrantLeft + quadrantLeft +
quadrantWidth + quadrantWidth +
this.config.quadrantPadding, this.config.quadrantPadding,
y: quadrantTop + quadrantHalfHeight - (drawAxisLabelInMiddle ? quadrantHalfHeight / 2 : 0), y:
quadrantTop + quadrantHalfHeight - (drawYAxisLabelsInMiddle ? quadrantHalfHeight / 2 : 0),
fontSize: this.config.yAxisLabelFontSize, fontSize: this.config.yAxisLabelFontSize,
verticalPos: drawAxisLabelInMiddle ? 'center' : 'left', verticalPos: drawYAxisLabelsInMiddle ? 'center' : 'left',
horizontalPos: 'top', horizontalPos: 'top',
rotation: -90, rotation: -90,
}); });

View File

@ -1,4 +1,4 @@
import * as configApi from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { sanitizeText } from '../common/common.js'; import { sanitizeText } from '../common/common.js';
import { import {
setAccTitle, setAccTitle,
@ -11,7 +11,7 @@ import {
} from '../common/commonDb.js'; } from '../common/commonDb.js';
import { QuadrantBuilder } from './quadrantBuilder.js'; import { QuadrantBuilder } from './quadrantBuilder.js';
const config = configApi.getConfig(); const config = getConfig();
function textSanitizer(text: string) { function textSanitizer(text: string) {
return sanitizeText(text.trim(), config); return sanitizeText(text.trim(), config);
@ -66,7 +66,7 @@ function setHeight(height: number) {
} }
function getQuadrantData() { function getQuadrantData() {
const config = configApi.getConfig(); const config = getConfig();
const { themeVariables, quadrantChart: quadrantChartConfig } = config; const { themeVariables, quadrantChart: quadrantChartConfig } = config;
if (quadrantChartConfig) { if (quadrantChartConfig) {
quadrantBuilder.setConfig(quadrantChartConfig); quadrantBuilder.setConfig(quadrantChartConfig);

View File

@ -1,6 +1,6 @@
// @ts-nocheck - don't check until handle it // @ts-nocheck - don't check until handle it
import { select } from 'd3'; import { select } from 'd3';
import * as configApi from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import { configureSvgSize } from '../../setupGraphViewbox.js'; import { configureSvgSize } from '../../setupGraphViewbox.js';
import type { Diagram } from '../../Diagram.js'; import type { Diagram } from '../../Diagram.js';
@ -27,7 +27,7 @@ export const draw = (txt: string, id: string, _version: string, diagObj: Diagram
return `translate(${data.x}, ${data.y}) rotate(${data.rotation || 0})`; return `translate(${data.x}, ${data.y}) rotate(${data.rotation || 0})`;
} }
const conf = configApi.getConfig(); const conf = getConfig();
log.debug('Rendering quadrant chart\n' + txt); log.debug('Rendering quadrant chart\n' + txt);

View File

@ -1,4 +1,4 @@
import * as configApi from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import { import {
@ -144,7 +144,7 @@ export default {
VerifyType, VerifyType,
Relationships, Relationships,
getConfig: () => configApi.getConfig().req, getConfig: () => getConfig().req,
addRequirement, addRequirement,
getRequirements, getRequirements,

View File

@ -5,7 +5,7 @@ import { log } from '../../logger.js';
import { configureSvgSize } from '../../setupGraphViewbox.js'; import { configureSvgSize } from '../../setupGraphViewbox.js';
import common from '../common/common.js'; import common from '../common/common.js';
import markers from './requirementMarkers.js'; import markers from './requirementMarkers.js';
import { getConfig } from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
let conf = {}; let conf = {};
let relCnt = 0; let relCnt = 0;

View File

@ -1,4 +1,4 @@
import * as configApi from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import common from '../common/common.js'; import common from '../common/common.js';
import { import {
setAccTitle, setAccTitle,
@ -42,7 +42,7 @@ class SankeyNode {
} }
const findOrCreateNode = (ID: string): SankeyNode => { const findOrCreateNode = (ID: string): SankeyNode => {
ID = common.sanitizeText(ID, configApi.getConfig()); ID = common.sanitizeText(ID, getConfig());
if (!nodesMap[ID]) { if (!nodesMap[ID]) {
nodesMap[ID] = new SankeyNode(ID); nodesMap[ID] = new SankeyNode(ID);
@ -65,7 +65,7 @@ const getGraph = () => ({
export default { export default {
nodesMap, nodesMap,
getConfig: () => configApi.getConfig().sankey, getConfig: () => getConfig().sankey,
getNodes, getNodes,
getLinks, getLinks,
getGraph, getGraph,

View File

@ -1,5 +1,5 @@
import type { Diagram } from '../../Diagram.js'; import type { Diagram } from '../../Diagram.js';
import * as configApi from '../../config.js'; import { getConfig, defaultConfig } from '../../diagram-api/diagramAPI.js';
import { import {
select as d3select, select as d3select,
@ -41,8 +41,8 @@ const alignmentsMap: Record<
*/ */
export const draw = function (text: string, id: string, _version: string, diagObj: Diagram): void { export const draw = function (text: string, id: string, _version: string, diagObj: Diagram): void {
// Get Sankey config // Get Sankey config
const { securityLevel, sankey: conf } = configApi.getConfig(); const { securityLevel, sankey: conf } = getConfig();
const defaultSankeyConfig = configApi!.defaultConfig!.sankey!; const defaultSankeyConfig = defaultConfig!.sankey!;
// TODO: // TODO:
// This code repeats for every diagram // This code repeats for every diagram

View File

@ -1,4 +1,4 @@
import * as configApi from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import { sanitizeText } from '../common/common.js'; import { sanitizeText } from '../common/common.js';
import { import {
@ -196,7 +196,7 @@ export const autoWrap = () => {
if (wrapEnabled !== undefined) { if (wrapEnabled !== undefined) {
return wrapEnabled; return wrapEnabled;
} }
return configApi.getConfig().sequence.wrap; return getConfig().sequence.wrap;
}; };
export const clear = function () { export const clear = function () {
@ -251,7 +251,7 @@ export const parseBoxData = function (str) {
color: color, color: color,
text: text:
title !== undefined title !== undefined
? sanitizeText(title.replace(/^:?(?:no)?wrap:/, ''), configApi.getConfig()) ? sanitizeText(title.replace(/^:?(?:no)?wrap:/, ''), getConfig())
: undefined, : undefined,
wrap: wrap:
title !== undefined title !== undefined
@ -337,7 +337,7 @@ export const addLinks = function (actorId, text) {
const actor = getActor(actorId); const actor = getActor(actorId);
// JSON.parse the text // JSON.parse the text
try { try {
let sanitizedText = sanitizeText(text.text, configApi.getConfig()); let sanitizedText = sanitizeText(text.text, getConfig());
sanitizedText = sanitizedText.replace(/&amp;/g, '&'); sanitizedText = sanitizedText.replace(/&amp;/g, '&');
sanitizedText = sanitizedText.replace(/&equals;/g, '='); sanitizedText = sanitizedText.replace(/&equals;/g, '=');
const links = JSON.parse(sanitizedText); const links = JSON.parse(sanitizedText);
@ -353,7 +353,7 @@ export const addALink = function (actorId, text) {
const actor = getActor(actorId); const actor = getActor(actorId);
try { try {
const links = {}; const links = {};
let sanitizedText = sanitizeText(text.text, configApi.getConfig()); let sanitizedText = sanitizeText(text.text, getConfig());
var sep = sanitizedText.indexOf('@'); var sep = sanitizedText.indexOf('@');
sanitizedText = sanitizedText.replace(/&amp;/g, '&'); sanitizedText = sanitizedText.replace(/&amp;/g, '&');
sanitizedText = sanitizedText.replace(/&equals;/g, '='); sanitizedText = sanitizedText.replace(/&equals;/g, '=');
@ -387,7 +387,7 @@ export const addProperties = function (actorId, text) {
const actor = getActor(actorId); const actor = getActor(actorId);
// JSON.parse the text // JSON.parse the text
try { try {
let sanitizedText = sanitizeText(text.text, configApi.getConfig()); let sanitizedText = sanitizeText(text.text, getConfig());
const properties = JSON.parse(sanitizedText); const properties = JSON.parse(sanitizedText);
// add the deserialized text to the actor's property field. // add the deserialized text to the actor's property field.
insertProperties(actor, properties); insertProperties(actor, properties);
@ -629,7 +629,7 @@ export default {
getBoxes, getBoxes,
getDiagramTitle, getDiagramTitle,
setDiagramTitle, setDiagramTitle,
getConfig: () => configApi.getConfig().sequence, getConfig: () => getConfig().sequence,
clear, clear,
parseMessage, parseMessage,
parseBoxData, parseBoxData,

View File

@ -1,5 +1,5 @@
import { vi } from 'vitest'; import { vi } from 'vitest';
import * as configApi from '../../config.js'; import { setSiteConfig } from '../../diagram-api/diagramAPI.js';
import mermaidAPI from '../../mermaidAPI.js'; import mermaidAPI from '../../mermaidAPI.js';
import { Diagram, getDiagramFromText } from '../../Diagram.js'; import { Diagram, getDiagramFromText } from '../../Diagram.js';
import { addDiagrams } from '../../diagram-api/diagram-orchestration.js'; import { addDiagrams } from '../../diagram-api/diagram-orchestration.js';
@ -1610,7 +1610,7 @@ describe('when rendering a sequenceDiagram APA', function () {
wrap: false, wrap: false,
mirrorActors: false, mirrorActors: false,
}; };
configApi.setSiteConfig({ logLevel: 5, sequence: conf }); setSiteConfig({ logLevel: 5, sequence: conf });
}); });
let conf; let conf;
beforeEach(function () { beforeEach(function () {
@ -1631,7 +1631,7 @@ describe('when rendering a sequenceDiagram APA', function () {
wrap: false, wrap: false,
mirrorActors: false, mirrorActors: false,
}; };
configApi.setSiteConfig({ logLevel: 5, sequence: conf }); setSiteConfig({ logLevel: 5, sequence: conf });
diagram = new Diagram(` diagram = new Diagram(`
sequenceDiagram sequenceDiagram
Alice->Bob:Hello Bob, how are you? Alice->Bob:Hello Bob, how are you?

View File

@ -4,7 +4,7 @@ import svgDraw, { ACTOR_TYPE_WIDTH, drawText, fixLifeLineHeights } from './svgDr
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import common from '../common/common.js'; import common from '../common/common.js';
import * as svgDrawCommon from '../common/svgDrawCommon.js'; import * as svgDrawCommon from '../common/svgDrawCommon.js';
import * as configApi from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import assignWithDepth from '../../assignWithDepth.js'; import assignWithDepth from '../../assignWithDepth.js';
import utils from '../../utils.js'; import utils from '../../utils.js';
import { configureSvgSize } from '../../setupGraphViewbox.js'; import { configureSvgSize } from '../../setupGraphViewbox.js';
@ -91,7 +91,7 @@ export const bounds = {
stopy: undefined, stopy: undefined,
}; };
this.verticalPos = 0; this.verticalPos = 0;
setConf(configApi.getConfig()); setConf(getConfig());
}, },
updateVal: function (obj, key, val, fun) { updateVal: function (obj, key, val, fun) {
if (obj[key] === undefined) { if (obj[key] === undefined) {
@ -747,7 +747,7 @@ function adjustCreatedDestroyedData(
* @param diagObj - A standard diagram containing the db and the text and type etc of the diagram * @param diagObj - A standard diagram containing the db and the text and type etc of the diagram
*/ */
export const draw = function (_text: string, id: string, _version: string, diagObj: Diagram) { export const draw = function (_text: string, id: string, _version: string, diagObj: Diagram) {
const { securityLevel, sequence } = configApi.getConfig(); const { securityLevel, sequence } = getConfig();
conf = sequence; conf = sequence;
// Handle root and Document for when rendering in sandbox mode // Handle root and Document for when rendering in sandbox mode
let sandboxElement; let sandboxElement;

View File

@ -3,7 +3,7 @@ import idCache from './id-cache.js';
import stateDb from './stateDb.js'; import stateDb from './stateDb.js';
import utils from '../../utils.js'; import utils from '../../utils.js';
import common from '../common/common.js'; import common from '../common/common.js';
import { getConfig } from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
/** /**

View File

@ -1,7 +1,7 @@
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import { generateId } from '../../utils.js'; import { generateId } from '../../utils.js';
import common from '../common/common.js'; import common from '../common/common.js';
import * as configApi from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { import {
setAccTitle, setAccTitle,
getAccTitle, getAccTitle,
@ -253,7 +253,7 @@ export const addState = function (
currentDocument.states[trimmedId].note = note; currentDocument.states[trimmedId].note = note;
currentDocument.states[trimmedId].note.text = common.sanitizeText( currentDocument.states[trimmedId].note.text = common.sanitizeText(
currentDocument.states[trimmedId].note.text, currentDocument.states[trimmedId].note.text,
configApi.getConfig() getConfig()
); );
} }
@ -398,7 +398,7 @@ export function addRelationObjs(item1, item2, relationTitle) {
currentDocument.relations.push({ currentDocument.relations.push({
id1, id1,
id2, id2,
relationTitle: common.sanitizeText(relationTitle, configApi.getConfig()), relationTitle: common.sanitizeText(relationTitle, getConfig()),
}); });
} }
@ -423,7 +423,7 @@ export const addRelation = function (item1, item2, title) {
currentDocument.relations.push({ currentDocument.relations.push({
id1, id1,
id2, id2,
title: common.sanitizeText(title, configApi.getConfig()), title: common.sanitizeText(title, getConfig()),
}); });
} }
}; };
@ -431,7 +431,7 @@ export const addRelation = function (item1, item2, title) {
export const addDescription = function (id, descr) { export const addDescription = function (id, descr) {
const theState = currentDocument.states[id]; const theState = currentDocument.states[id];
const _descr = descr.startsWith(':') ? descr.replace(':', '').trim() : descr; const _descr = descr.startsWith(':') ? descr.replace(':', '').trim() : descr;
theState.descriptions.push(common.sanitizeText(_descr, configApi.getConfig())); theState.descriptions.push(common.sanitizeText(_descr, getConfig()));
}; };
export const cleanupLabel = function (label) { export const cleanupLabel = function (label) {
@ -542,7 +542,7 @@ const setDirection = (dir) => {
const trimColon = (str) => (str && str[0] === ':' ? str.substr(1).trim() : str.trim()); const trimColon = (str) => (str && str[0] === ':' ? str.substr(1).trim() : str.trim());
export default { export default {
getConfig: () => configApi.getConfig().state, getConfig: () => getConfig().state,
addState, addState,
clear, clear,
getState, getState,

View File

@ -212,14 +212,14 @@ describe('state diagram, ', function () {
parser.parse(str); parser.parse(str);
}); });
it('should handle state defintions with separation of id', function () { it('should handle state definitions with separation of id', function () {
const str = `stateDiagram\n const str = `stateDiagram\n
state "Long state description" as state1 state "Long state description" as state1
`; `;
parser.parse(str); parser.parse(str);
}); });
it('should handle state defintions with separation of id', function () { it('should handle state definitions with separation of id', function () {
const str = `stateDiagram const str = `stateDiagram
state "Not Shooting State" as NotShooting { state "Not Shooting State" as NotShooting {
state "Idle mode" as Idle state "Idle mode" as Idle
@ -360,7 +360,7 @@ describe('state diagram, ', function () {
parser.parse(str); parser.parse(str);
}); });
it('should handle notes for composit states', function () { it('should handle notes for composite states', function () {
const str = `stateDiagram\n const str = `stateDiagram\n
[*] --> NotShooting [*] --> NotShooting

View File

@ -1,6 +1,6 @@
import * as graphlib from 'dagre-d3-es/src/graphlib/index.js'; import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
import { select } from 'd3'; import { select } from 'd3';
import { getConfig } from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { render } from '../../dagre-wrapper/index.js'; import { render } from '../../dagre-wrapper/index.js';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import { configureSvgSize } from '../../setupGraphViewbox.js'; import { configureSvgSize } from '../../setupGraphViewbox.js';

View File

@ -4,7 +4,7 @@ import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import common from '../common/common.js'; import common from '../common/common.js';
import { drawState, addTitleAndBox, drawEdge } from './shapes.js'; import { drawState, addTitleAndBox, drawEdge } from './shapes.js';
import { getConfig } from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { configureSvgSize } from '../../setupGraphViewbox.js'; import { configureSvgSize } from '../../setupGraphViewbox.js';
// TODO Move conf object to main conf in mermaidAPI // TODO Move conf object to main conf in mermaidAPI

View File

@ -3,7 +3,7 @@ import type { Selection } from 'd3';
import { select } from 'd3'; import { select } from 'd3';
import svgDraw from './svgDraw.js'; import svgDraw from './svgDraw.js';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import { getConfig } from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { setupGraphViewbox } from '../../setupGraphViewbox.js'; import { setupGraphViewbox } from '../../setupGraphViewbox.js';
import type { Diagram } from '../../Diagram.js'; import type { Diagram } from '../../Diagram.js';
import type { MermaidConfig } from '../../config.type.js'; import type { MermaidConfig } from '../../config.type.js';

View File

@ -1,4 +1,4 @@
import * as configApi from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { import {
setAccTitle, setAccTitle,
getAccTitle, getAccTitle,
@ -113,7 +113,7 @@ const getActors = function () {
}; };
export default { export default {
getConfig: () => configApi.getConfig().journey, getConfig: () => getConfig().journey,
clear, clear,
setDiagramTitle, setDiagramTitle,
getDiagramTitle, getDiagramTitle,

View File

@ -1,7 +1,7 @@
// @ts-nocheck TODO: fix file // @ts-nocheck TODO: fix file
import { select } from 'd3'; import { select } from 'd3';
import svgDraw from './svgDraw.js'; import svgDraw from './svgDraw.js';
import { getConfig } from '../../config.js'; import { getConfig } from '../../diagram-api/diagramAPI.js';
import { configureSvgSize } from '../../setupGraphViewbox.js'; import { configureSvgSize } from '../../setupGraphViewbox.js';
export const setConf = function (cnf) { export const setConf = function (cnf) {

View File

@ -0,0 +1,45 @@
import type { ScaleBand } from 'd3';
import { scaleBand } from 'd3';
import { log } from '../../../../../logger.js';
import type { TextDimensionCalculator } from '../../textDimensionCalculator.js';
import { BaseAxis } from './baseAxis.js';
import type { XYChartAxisThemeConfig, XYChartAxisConfig } from '../../interfaces.js';
export class BandAxis extends BaseAxis {
private scale: ScaleBand<string>;
private categories: string[];
constructor(
axisConfig: XYChartAxisConfig,
axisThemeConfig: XYChartAxisThemeConfig,
categories: string[],
title: string,
textDimensionCalculator: TextDimensionCalculator
) {
super(axisConfig, title, textDimensionCalculator, axisThemeConfig);
this.categories = categories;
this.scale = scaleBand().domain(this.categories).range(this.getRange());
}
setRange(range: [number, number]): void {
super.setRange(range);
}
recalculateScale(): void {
this.scale = scaleBand()
.domain(this.categories)
.range(this.getRange())
.paddingInner(1)
.paddingOuter(0)
.align(0.5);
log.trace('BandAxis axis final categories, range: ', this.categories, this.getRange());
}
getTickValues(): (string | number)[] {
return this.categories;
}
getScaleValue(value: string): number {
return this.scale(value) || this.getRange()[0];
}
}

View File

@ -0,0 +1,422 @@
import type {
BoundingRect,
Dimension,
DrawableElem,
Point,
XYChartAxisConfig,
XYChartAxisThemeConfig,
} from '../../interfaces.js';
import type { TextDimensionCalculator } from '../../textDimensionCalculator.js';
import type { Axis, AxisPosition } from './index.js';
const BAR_WIDTH_TO_TICK_WIDTH_RATIO = 0.7;
const MAX_OUTER_PADDING_PERCENT_FOR_WRT_LABEL = 0.2;
export abstract class BaseAxis implements Axis {
protected boundingRect: BoundingRect = { x: 0, y: 0, width: 0, height: 0 };
protected axisPosition: AxisPosition = 'left';
private range: [number, number];
protected showTitle = false;
protected showLabel = false;
protected showTick = false;
protected showAxisLine = false;
protected outerPadding = 0;
protected titleTextHeight = 0;
protected labelTextHeight = 0;
constructor(
protected axisConfig: XYChartAxisConfig,
protected title: string,
protected textDimensionCalculator: TextDimensionCalculator,
protected axisThemeConfig: XYChartAxisThemeConfig
) {
this.range = [0, 10];
this.boundingRect = { x: 0, y: 0, width: 0, height: 0 };
this.axisPosition = 'left';
}
setRange(range: [number, number]): void {
this.range = range;
if (this.axisPosition === 'left' || this.axisPosition === 'right') {
this.boundingRect.height = range[1] - range[0];
} else {
this.boundingRect.width = range[1] - range[0];
}
this.recalculateScale();
}
getRange(): [number, number] {
return [this.range[0] + this.outerPadding, this.range[1] - this.outerPadding];
}
setAxisPosition(axisPosition: AxisPosition): void {
this.axisPosition = axisPosition;
this.setRange(this.range);
}
abstract getScaleValue(value: number | string): number;
abstract recalculateScale(): void;
abstract getTickValues(): Array<string | number>;
getTickDistance(): number {
const range = this.getRange();
return Math.abs(range[0] - range[1]) / this.getTickValues().length;
}
getAxisOuterPadding(): number {
return this.outerPadding;
}
private getLabelDimension(): Dimension {
return this.textDimensionCalculator.getMaxDimension(
this.getTickValues().map((tick) => tick.toString()),
this.axisConfig.labelFontSize
);
}
recalculateOuterPaddingToDrawBar(): void {
if (BAR_WIDTH_TO_TICK_WIDTH_RATIO * this.getTickDistance() > this.outerPadding * 2) {
this.outerPadding = Math.floor((BAR_WIDTH_TO_TICK_WIDTH_RATIO * this.getTickDistance()) / 2);
}
this.recalculateScale();
}
private calculateSpaceIfDrawnHorizontally(availableSpace: Dimension) {
let availableHeight = availableSpace.height;
if (this.axisConfig.showAxisLine && availableHeight > this.axisConfig.axisLineWidth) {
availableHeight -= this.axisConfig.axisLineWidth;
this.showAxisLine = true;
}
if (this.axisConfig.showLabel) {
const spaceRequired = this.getLabelDimension();
const maxPadding = MAX_OUTER_PADDING_PERCENT_FOR_WRT_LABEL * availableSpace.width;
this.outerPadding = Math.min(spaceRequired.width / 2, maxPadding);
const heightRequired = spaceRequired.height + this.axisConfig.labelPadding * 2;
this.labelTextHeight = spaceRequired.height;
if (heightRequired <= availableHeight) {
availableHeight -= heightRequired;
this.showLabel = true;
}
}
if (this.axisConfig.showTick && availableHeight >= this.axisConfig.tickLength) {
this.showTick = true;
availableHeight -= this.axisConfig.tickLength;
}
if (this.axisConfig.showTitle && this.title) {
const spaceRequired = this.textDimensionCalculator.getMaxDimension(
[this.title],
this.axisConfig.titleFontSize
);
const heightRequired = spaceRequired.height + this.axisConfig.titlePadding * 2;
this.titleTextHeight = spaceRequired.height;
if (heightRequired <= availableHeight) {
availableHeight -= heightRequired;
this.showTitle = true;
}
}
this.boundingRect.width = availableSpace.width;
this.boundingRect.height = availableSpace.height - availableHeight;
}
private calculateSpaceIfDrawnVertical(availableSpace: Dimension) {
let availableWidth = availableSpace.width;
if (this.axisConfig.showAxisLine && availableWidth > this.axisConfig.axisLineWidth) {
availableWidth -= this.axisConfig.axisLineWidth;
this.showAxisLine = true;
}
if (this.axisConfig.showLabel) {
const spaceRequired = this.getLabelDimension();
const maxPadding = MAX_OUTER_PADDING_PERCENT_FOR_WRT_LABEL * availableSpace.height;
this.outerPadding = Math.min(spaceRequired.height / 2, maxPadding);
const widthRequired = spaceRequired.width + this.axisConfig.labelPadding * 2;
if (widthRequired <= availableWidth) {
availableWidth -= widthRequired;
this.showLabel = true;
}
}
if (this.axisConfig.showTick && availableWidth >= this.axisConfig.tickLength) {
this.showTick = true;
availableWidth -= this.axisConfig.tickLength;
}
if (this.axisConfig.showTitle && this.title) {
const spaceRequired = this.textDimensionCalculator.getMaxDimension(
[this.title],
this.axisConfig.titleFontSize
);
const widthRequired = spaceRequired.height + this.axisConfig.titlePadding * 2;
this.titleTextHeight = spaceRequired.height;
if (widthRequired <= availableWidth) {
availableWidth -= widthRequired;
this.showTitle = true;
}
}
this.boundingRect.width = availableSpace.width - availableWidth;
this.boundingRect.height = availableSpace.height;
}
calculateSpace(availableSpace: Dimension): Dimension {
if (this.axisPosition === 'left' || this.axisPosition === 'right') {
this.calculateSpaceIfDrawnVertical(availableSpace);
} else {
this.calculateSpaceIfDrawnHorizontally(availableSpace);
}
this.recalculateScale();
return {
width: this.boundingRect.width,
height: this.boundingRect.height,
};
}
setBoundingBoxXY(point: Point): void {
this.boundingRect.x = point.x;
this.boundingRect.y = point.y;
}
private getDrawableElementsForLeftAxis(): DrawableElem[] {
const drawableElement: DrawableElem[] = [];
if (this.showAxisLine) {
const x = this.boundingRect.x + this.boundingRect.width - this.axisConfig.axisLineWidth / 2;
drawableElement.push({
type: 'path',
groupTexts: ['left-axis', 'axisl-line'],
data: [
{
path: `M ${x},${this.boundingRect.y} L ${x},${
this.boundingRect.y + this.boundingRect.height
} `,
strokeFill: this.axisThemeConfig.axisLineColor,
strokeWidth: this.axisConfig.axisLineWidth,
},
],
});
}
if (this.showLabel) {
drawableElement.push({
type: 'text',
groupTexts: ['left-axis', 'label'],
data: this.getTickValues().map((tick) => ({
text: tick.toString(),
x:
this.boundingRect.x +
this.boundingRect.width -
(this.showLabel ? this.axisConfig.labelPadding : 0) -
(this.showTick ? this.axisConfig.tickLength : 0) -
(this.showAxisLine ? this.axisConfig.axisLineWidth : 0),
y: this.getScaleValue(tick),
fill: this.axisThemeConfig.labelColor,
fontSize: this.axisConfig.labelFontSize,
rotation: 0,
verticalPos: 'middle',
horizontalPos: 'right',
})),
});
}
if (this.showTick) {
const x =
this.boundingRect.x +
this.boundingRect.width -
(this.showAxisLine ? this.axisConfig.axisLineWidth : 0);
drawableElement.push({
type: 'path',
groupTexts: ['left-axis', 'ticks'],
data: this.getTickValues().map((tick) => ({
path: `M ${x},${this.getScaleValue(tick)} L ${
x - this.axisConfig.tickLength
},${this.getScaleValue(tick)}`,
strokeFill: this.axisThemeConfig.tickColor,
strokeWidth: this.axisConfig.tickWidth,
})),
});
}
if (this.showTitle) {
drawableElement.push({
type: 'text',
groupTexts: ['left-axis', 'title'],
data: [
{
text: this.title,
x: this.boundingRect.x + this.axisConfig.titlePadding,
y: this.boundingRect.y + this.boundingRect.height / 2,
fill: this.axisThemeConfig.titleColor,
fontSize: this.axisConfig.titleFontSize,
rotation: 270,
verticalPos: 'top',
horizontalPos: 'center',
},
],
});
}
return drawableElement;
}
private getDrawableElementsForBottomAxis(): DrawableElem[] {
const drawableElement: DrawableElem[] = [];
if (this.showAxisLine) {
const y = this.boundingRect.y + this.axisConfig.axisLineWidth / 2;
drawableElement.push({
type: 'path',
groupTexts: ['bottom-axis', 'axis-line'],
data: [
{
path: `M ${this.boundingRect.x},${y} L ${
this.boundingRect.x + this.boundingRect.width
},${y}`,
strokeFill: this.axisThemeConfig.axisLineColor,
strokeWidth: this.axisConfig.axisLineWidth,
},
],
});
}
if (this.showLabel) {
drawableElement.push({
type: 'text',
groupTexts: ['bottom-axis', 'label'],
data: this.getTickValues().map((tick) => ({
text: tick.toString(),
x: this.getScaleValue(tick),
y:
this.boundingRect.y +
this.axisConfig.labelPadding +
(this.showTick ? this.axisConfig.tickLength : 0) +
(this.showAxisLine ? this.axisConfig.axisLineWidth : 0),
fill: this.axisThemeConfig.labelColor,
fontSize: this.axisConfig.labelFontSize,
rotation: 0,
verticalPos: 'top',
horizontalPos: 'center',
})),
});
}
if (this.showTick) {
const y = this.boundingRect.y + (this.showAxisLine ? this.axisConfig.axisLineWidth : 0);
drawableElement.push({
type: 'path',
groupTexts: ['bottom-axis', 'ticks'],
data: this.getTickValues().map((tick) => ({
path: `M ${this.getScaleValue(tick)},${y} L ${this.getScaleValue(tick)},${
y + this.axisConfig.tickLength
}`,
strokeFill: this.axisThemeConfig.tickColor,
strokeWidth: this.axisConfig.tickWidth,
})),
});
}
if (this.showTitle) {
drawableElement.push({
type: 'text',
groupTexts: ['bottom-axis', 'title'],
data: [
{
text: this.title,
x: this.range[0] + (this.range[1] - this.range[0]) / 2,
y:
this.boundingRect.y +
this.boundingRect.height -
this.axisConfig.titlePadding -
this.titleTextHeight,
fill: this.axisThemeConfig.titleColor,
fontSize: this.axisConfig.titleFontSize,
rotation: 0,
verticalPos: 'top',
horizontalPos: 'center',
},
],
});
}
return drawableElement;
}
private getDrawableElementsForTopAxis(): DrawableElem[] {
const drawableElement: DrawableElem[] = [];
if (this.showAxisLine) {
const y = this.boundingRect.y + this.boundingRect.height - this.axisConfig.axisLineWidth / 2;
drawableElement.push({
type: 'path',
groupTexts: ['top-axis', 'axis-line'],
data: [
{
path: `M ${this.boundingRect.x},${y} L ${
this.boundingRect.x + this.boundingRect.width
},${y}`,
strokeFill: this.axisThemeConfig.axisLineColor,
strokeWidth: this.axisConfig.axisLineWidth,
},
],
});
}
if (this.showLabel) {
drawableElement.push({
type: 'text',
groupTexts: ['top-axis', 'label'],
data: this.getTickValues().map((tick) => ({
text: tick.toString(),
x: this.getScaleValue(tick),
y:
this.boundingRect.y +
(this.showTitle ? this.titleTextHeight + this.axisConfig.titlePadding * 2 : 0) +
this.axisConfig.labelPadding,
fill: this.axisThemeConfig.labelColor,
fontSize: this.axisConfig.labelFontSize,
rotation: 0,
verticalPos: 'top',
horizontalPos: 'center',
})),
});
}
if (this.showTick) {
const y = this.boundingRect.y;
drawableElement.push({
type: 'path',
groupTexts: ['top-axis', 'ticks'],
data: this.getTickValues().map((tick) => ({
path: `M ${this.getScaleValue(tick)},${
y + this.boundingRect.height - (this.showAxisLine ? this.axisConfig.axisLineWidth : 0)
} L ${this.getScaleValue(tick)},${
y +
this.boundingRect.height -
this.axisConfig.tickLength -
(this.showAxisLine ? this.axisConfig.axisLineWidth : 0)
}`,
strokeFill: this.axisThemeConfig.tickColor,
strokeWidth: this.axisConfig.tickWidth,
})),
});
}
if (this.showTitle) {
drawableElement.push({
type: 'text',
groupTexts: ['top-axis', 'title'],
data: [
{
text: this.title,
x: this.boundingRect.x + this.boundingRect.width / 2,
y: this.boundingRect.y + this.axisConfig.titlePadding,
fill: this.axisThemeConfig.titleColor,
fontSize: this.axisConfig.titleFontSize,
rotation: 0,
verticalPos: 'top',
horizontalPos: 'center',
},
],
});
}
return drawableElement;
}
getDrawableElements(): DrawableElem[] {
if (this.axisPosition === 'left') {
return this.getDrawableElementsForLeftAxis();
}
if (this.axisPosition === 'right') {
throw Error('Drawing of right axis is not implemented');
}
if (this.axisPosition === 'bottom') {
return this.getDrawableElementsForBottomAxis();
}
if (this.axisPosition === 'top') {
return this.getDrawableElementsForTopAxis();
}
return [];
}
}

View File

@ -0,0 +1,47 @@
import type { Group } from '../../../../../diagram-api/types.js';
import type {
AxisDataType,
ChartComponent,
XYChartAxisConfig,
XYChartAxisThemeConfig,
} from '../../interfaces.js';
import { isBandAxisData } from '../../interfaces.js';
import { TextDimensionCalculatorWithFont } from '../../textDimensionCalculator.js';
import { BandAxis } from './bandAxis.js';
import { LinearAxis } from './linearAxis.js';
export type AxisPosition = 'left' | 'right' | 'top' | 'bottom';
export interface Axis extends ChartComponent {
getScaleValue(value: string | number): number;
setAxisPosition(axisPosition: AxisPosition): void;
getAxisOuterPadding(): number;
getTickDistance(): number;
recalculateOuterPaddingToDrawBar(): void;
setRange(range: [number, number]): void;
}
export function getAxis(
data: AxisDataType,
axisConfig: XYChartAxisConfig,
axisThemeConfig: XYChartAxisThemeConfig,
tmpSVGGroup: Group
): Axis {
const textDimansionCalculator = new TextDimensionCalculatorWithFont(tmpSVGGroup);
if (isBandAxisData(data)) {
return new BandAxis(
axisConfig,
axisThemeConfig,
data.categories,
data.title,
textDimansionCalculator
);
}
return new LinearAxis(
axisConfig,
axisThemeConfig,
[data.min, data.max],
data.title,
textDimansionCalculator
);
}

View File

@ -0,0 +1,38 @@
import type { ScaleLinear } from 'd3';
import { scaleLinear } from 'd3';
import type { TextDimensionCalculator } from '../../textDimensionCalculator.js';
import { BaseAxis } from './baseAxis.js';
import type { XYChartAxisThemeConfig, XYChartAxisConfig } from '../../interfaces.js';
export class LinearAxis extends BaseAxis {
private scale: ScaleLinear<number, number>;
private domain: [number, number];
constructor(
axisConfig: XYChartAxisConfig,
axisThemeConfig: XYChartAxisThemeConfig,
domain: [number, number],
title: string,
textDimensionCalculator: TextDimensionCalculator
) {
super(axisConfig, title, textDimensionCalculator, axisThemeConfig);
this.domain = domain;
this.scale = scaleLinear().domain(this.domain).range(this.getRange());
}
getTickValues(): (string | number)[] {
return this.scale.ticks();
}
recalculateScale(): void {
const domain = [...this.domain]; // copy the array so if reverse is called two times it should not cancel the reverse effect
if (this.axisPosition === 'left') {
domain.reverse(); // since y-axis in svg start from top
}
this.scale = scaleLinear().domain(domain).range(this.getRange());
}
getScaleValue(value: number): number {
return this.scale(value);
}
}

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