Merge branches 'knsv/new-shapes' and 'knsv/new-shapes' of github.com:mermaid-js/mermaid into knsv/new-shapes

This commit is contained in:
Knut Sveidqvist 2024-08-13 13:16:47 +02:00
commit 4d401c127d
80 changed files with 3330 additions and 3672 deletions

View File

@ -9,7 +9,7 @@ elems
gantt
gitgraph
gzipped
handdrawn
handDrawn
knsv
Knut
marginx

View File

@ -1,6 +1,6 @@
BRANDES
circo
handdrawn
handDrawn
KOEPF
neato
newbranch

View File

@ -38,4 +38,4 @@ jobs:
working-directory: ./packages/mermaid
run: pnpm run docs:build
- uses: autofix-ci/action@dd55f44df8f7cdb7a6bf74c78677eb8acd40cd0a
- uses: autofix-ci/action@ff86a557419858bb967097bfc916833f5647fa8c

View File

@ -1,14 +0,0 @@
import { urlSnapshotTest, openURLAndVerifyRendering } from '../../helpers/util.ts';
describe('Flowchart elk', () => {
it('should use dagre as fallback', () => {
urlSnapshotTest('http://localhost:9000/flow-elk.html', {
name: 'flow-elk fallback to dagre',
});
});
it('should allow overriding with external package', () => {
urlSnapshotTest('http://localhost:9000/flow-elk.html?elk=true', {
name: 'flow-elk overriding dagre with elk',
});
});
});

View File

@ -837,6 +837,26 @@ subgraph "\`**Two**\`"
in the hat\`") -- "\`1o **ipa**\`" --> d("The dog in the hog")
end
`,
{ flowchart: { titleTopMargin: 0 } }
);
});
it('Sub graphs and markdown strings', () => {
imgSnapshotTest(
`---
config:
layout: elk
---
flowchart LR
subgraph subgraph_ko6czgs5u["Untitled subgraph"]
D["Option 1"]
end
C{"Evaluate"} -- One --> D
C -- Two --> E(("Option 2"))
D --> E
A["A"]
`,
{ flowchart: { titleTopMargin: 0 } }
);
@ -875,11 +895,10 @@ describe('Title and arrow styling #4813', () => {
);
cy.get('svg').should((svg) => {
const edges = svg[0].querySelectorAll('.edges path');
// console.log(edges);
// expect(edges[0]).to.have.attr('pattern', 'solid');
// expect(edges[1]).to.have.attr('pattern', 'dotted');
// expect(edges[2]).to.have.css('stroke-width', '3.5px');
// expect(edges[3]).to.have.css('stroke-width', '1.5px');
expect(edges[0].getAttribute('class')).to.contain('edge-pattern-solid');
expect(edges[1].getAttribute('class')).to.contain('edge-pattern-dotted');
expect(edges[2].getAttribute('class')).to.contain('edge-thickness-thick');
expect(edges[3].getAttribute('class')).to.contain('edge-thickness-invisible');
});
});
});

File diff suppressed because it is too large Load Diff

View File

@ -30,13 +30,40 @@ describe('newShapes', () => {
it('4: should render new flippedTriangle shape', () => {
imgSnapshotTest(
`flowchart
KS --> AC@{ shape: flippedTriangle, label:"This is Final Label" }@
FS --> AD@{ shape: flippedTriangle, label:"This is Final Label" }@
FE --> AD
`,
{}
);
});
it('5: should render new hourGlass shape', () => {
imgSnapshotTest(
`flowchart
MS --> AE@{ shape: hourglass, label:"This is Final Label" }@
ME --> AE
`,
{}
);
});
it('6: should render new taggedRect shape', () => {
imgSnapshotTest(
`flowchart
KS --> AC@{ shape: taggedRect, label:"This is Final Label" }@
RE --> AC
`,
{}
);
});
it('5: should render new FlowChart for New Shapes', () => {
it('7: should render new multiRect shape', () => {
imgSnapshotTest(
`flowchart
DS --> AF@{ shape: multiRect, label:"This is Final Label" }@
DE --> AF
`,
{}
);
});
it('8: should render new FlowChart for New Shapes', () => {
renderGraph(
`
flowchart
@ -45,10 +72,13 @@ describe('newShapes', () => {
C@{ shape: tiltedCylinder, label: "write your Test Case"}@
D@{ shape: flippedTriangle, label: "new Test Case"}@
E@{ shape: waveRectangle, label: "Execute Test Case" }@
F@{ shape: slopedRect, label: "Test Passed?" }@
G@{ shape: bowTieRect, label: "Pass" }@
H@{ shape: dividedRect, label: "Log Defect" }@
I@{ shape: curvedTrapezoid, label: "End" }@
F@{ shape: hourglass , label: "add test case"}@
G@{ shape: taggedRect, label: "execute new test case"}@
H@{ shape: slopedRect, label: "Test Passed?" }@
I@{ shape: bowTieRect, label: "Pass" }@
J@{ shape: dividedRect, label: "Log Defect" }@
K@{ shape: curvedTrapezoid, label: "End" }@
L@{ shape: multiRect, label: "coming soon"}@
A --> B
B --> C
@ -56,9 +86,11 @@ describe('newShapes', () => {
D --> E
E --> F
F -->|Yes| G
F -->|No| H
G --> I
G -->|No| H
H --> I
I --> J
J --> K
K --> L
`,
{ flowchart: { useMaxWidth: true } }
);

View File

@ -134,7 +134,7 @@ flowchart LR
</td>
<td>
<pre id="diagram2" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
flowchart LR
id1([This is the text in the box])
</pre
@ -142,7 +142,7 @@ flowchart LR
</td>
<td>
<pre id="diagram3" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
flowchart LR
id1([This is the text in the box])
</pre
@ -150,7 +150,7 @@ flowchart LR
</td>
<td>
<pre id="diagram4" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
flowchart LR
id1([This is the text in the box])
</pre
@ -185,7 +185,7 @@ flowchart LR
</td>
<td>
<pre id="diagram6" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
flowchart LR
id1[[This is the text in the box]]
</pre
@ -193,7 +193,7 @@ flowchart LR
</td>
<td>
<pre id="diagram7" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
flowchart LR
id1[[This is the text in the box]]
</pre
@ -201,7 +201,7 @@ flowchart LR
</td>
<td>
<pre id="diagram8" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
flowchart LR
id1[[This is the text in the box]]
</pre
@ -236,7 +236,7 @@ flowchart LR
</td>
<td>
<pre id="diagram10" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
flowchart LR
id1[(Database)]
</pre
@ -244,7 +244,7 @@ flowchart LR
</td>
<td>
<pre id="diagram11" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
flowchart LR
id1[(Database)]
</pre
@ -252,7 +252,7 @@ flowchart LR
</td>
<td>
<pre id="diagram12" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
flowchart LR
id1[(Database)]
</pre
@ -287,7 +287,7 @@ flowchart LR
</td>
<td>
<pre id="diagram14" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
flowchart LR
id1((This is the text in the circle))
</pre
@ -295,7 +295,7 @@ flowchart LR
</td>
<td>
<pre id="diagram15" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
flowchart LR
id1((This is the text in the circle))
</pre
@ -303,7 +303,7 @@ flowchart LR
</td>
<td>
<pre id="diagram16" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
flowchart LR
id1((This is the text in the circle))
</pre
@ -338,7 +338,7 @@ flowchart LR
</td>
<td>
<pre id="diagram18" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
flowchart TD
id1(((This is the text in the circle)))
</pre
@ -346,7 +346,7 @@ flowchart LR
</td>
<td>
<pre id="diagram19" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
flowchart TD
id1(((This is the text in the circle)))
</pre
@ -354,7 +354,7 @@ flowchart LR
</td>
<td>
<pre id="diagram20" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
flowchart TD
id1(((This is the text in the circle)))
</pre
@ -389,7 +389,7 @@ flowchart LR
</td>
<td>
<pre id="diagram22" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
flowchart LR
id1>This is the text in the box]
</pre
@ -397,7 +397,7 @@ flowchart LR
</td>
<td>
<pre id="diagram23" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
flowchart LR
id1>This is the text in the box]
</pre
@ -405,7 +405,7 @@ flowchart LR
</td>
<td>
<pre id="diagram24" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
flowchart LR
id1>This is the text in the box]
</pre
@ -440,7 +440,7 @@ flowchart LR
</td>
<td>
<pre id="diagram26" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
flowchart LR
id1{This is the text in the box}
</pre
@ -448,7 +448,7 @@ flowchart LR
</td>
<td>
<pre id="diagram27" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
flowchart LR
id1{This is the text in the box}
</pre
@ -456,7 +456,7 @@ flowchart LR
</td>
<td>
<pre id="diagram28" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
flowchart LR
id1{This is the text in the box}
</pre
@ -491,7 +491,7 @@ flowchart LR
</td>
<td>
<pre id="diagram31" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
flowchart LR
id1{{This is the text in the box}}
</pre
@ -499,7 +499,7 @@ flowchart LR
</td>
<td>
<pre id="diagram32" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
flowchart LR
id1{{This is the text in the box}}
</pre
@ -534,7 +534,7 @@ flowchart LR
</td>
<td>
<pre id="diagram34" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
flowchart TD
id1[/This is the text in the box/]
</pre
@ -542,7 +542,7 @@ flowchart LR
</td>
<td>
<pre id="diagram35" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
flowchart TD
id1[/This is the text in the box/]
</pre
@ -550,7 +550,7 @@ flowchart LR
</td>
<td>
<pre id="diagram36" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
flowchart TD
id1[/This is the text in the box/]
</pre
@ -585,7 +585,7 @@ flowchart LR
</td>
<td>
<pre id="diagram38" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
flowchart TD
id1[\This is the text in the box\]
</pre
@ -593,7 +593,7 @@ flowchart LR
</td>
<td>
<pre id="diagram39" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
flowchart TD
id1[\This is the text in the box\]
</pre
@ -601,7 +601,7 @@ flowchart LR
</td>
<td>
<pre id="diagram40" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
flowchart TD
id1[\This is the text in the box\]
@ -637,7 +637,7 @@ flowchart LR
</td>
<td>
<pre id="diagram42" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
flowchart TD
A[/Christmas\]
</pre
@ -645,7 +645,7 @@ flowchart LR
</td>
<td>
<pre id="diagram43" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
flowchart TD
A[/Christmas\]
</pre
@ -653,7 +653,7 @@ flowchart LR
</td>
<td>
<pre id="diagram44" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
flowchart TD
A[/Christmas\]
</pre
@ -688,7 +688,7 @@ flowchart LR
</td>
<td>
<pre id="diagram46" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
flowchart TD
A[\Christmas/]
</pre
@ -696,7 +696,7 @@ flowchart LR
</td>
<td>
<pre id="diagram47" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
flowchart TD
A[\Christmas/]
</pre
@ -704,7 +704,7 @@ flowchart LR
</td>
<td>
<pre id="diagram48" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
flowchart TD
A[\Christmas/]
</pre
@ -739,7 +739,7 @@ flowchart LR
</td>
<td>
<pre id="diagram50" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
flowchart LR
id1(This is the text in the box)
</pre
@ -747,7 +747,7 @@ flowchart LR
</td>
<td>
<pre id="diagram51" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
flowchart LR
id1(This is the text in the box)
</pre
@ -755,7 +755,7 @@ flowchart LR
</td>
<td>
<pre id="diagram52" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
flowchart LR
id1(This is the text in the box)
</pre
@ -790,7 +790,7 @@ flowchart LR
</td>
<td>
<pre id="diagram54" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
flowchart LR
id1[This is the text in the box]
</pre
@ -798,7 +798,7 @@ flowchart LR
</td>
<td>
<pre id="diagram55" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
flowchart LR
id1[This is the text in the box]
</pre
@ -806,7 +806,7 @@ flowchart LR
</td>
<td>
<pre id="diagram56" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
flowchart LR
id1[This is the text in the box]
</pre
@ -827,7 +827,7 @@ flowchart LR
mermaid.parseError = function (err, hash) {};
mermaid.initialize({
handdrawn: false,
handDrawn: false,
mergeEdges: true,
layout: 'dagre',
flowchart: { titleTopMargin: 10 },

View File

@ -125,7 +125,7 @@
</th>
<td>
<pre id="diagram1" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
stateDiagram-v2
stateA
@ -134,7 +134,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram2" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
flowchart LR
id1[[This is the text in the box]]
@ -152,7 +152,7 @@ flowchart LR
mermaid.parseError = function (err, hash) {};
mermaid.initialize({
handdrawn: false,
handDrawn: false,
mergeEdges: true,
layout: 'dagre',
flowchart: { titleTopMargin: 10 },

View File

@ -1,40 +1,54 @@
<html>
<head>
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
/>
<link
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
rel="stylesheet"
/>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&display=swap"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css2?family=Caveat:wght@400..700&family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
rel="stylesheet"
/>
<head>
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" />
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap" rel="stylesheet" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Caveat:wght@400..700&family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
rel="stylesheet" />
<link href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
rel="stylesheet" />
<style>
body {
/* background: rgb(221, 208, 208); */
/* background: #333; */
font-family: 'Arial';
/* font-size: 18px !important; */
}
<style>
body {
/* background: rgb(221, 208, 208); */
/* background: #333; */
font-family: 'Arial';
/* font-size: 18px !important; */
}
h1 {
color: grey;
}
h1 {
color: grey;
}
.mermaid2 {
display: none;
}
.mermaid2 {
display: none;
}
.mermaid svg {
/* font-size: 18px !important; */
.mermaid svg {
/* font-size: 18px !important; */
/* background-color: #efefef;
/* background-color: #efefef;
background-image: radial-gradient(#fff 51%, transparent 91%),
radial-gradient(#fff 51%, transparent 91%);
background-size: 20px 20px;
@ -42,19 +56,20 @@
0 0,
10px 10px;
background-repeat: repeat; */
}
</style>
</head>
}
</style>
</head>
<body>
<pre id="diagram4" class="mermaid">
<body>
<pre id="diagram4" class="mermaid">
flowchart
node_3@{ shape: triangle }@
</pre>
<pre id="diagram4" class="mermaid2">
</pre
>
<pre id="diagram4" class="mermaid2">
flowchart
A{"This is a label"}@{
@ -73,51 +88,51 @@ flowchart
icon: car
}@ --> B
A(This is a label)
</pre>
</pre
>
<script type="module">
import mermaid from './mermaid.esm.mjs';
import { layouts } from './mermaid-layout-elk.esm.mjs';
mermaid.registerLayoutLoaders(layouts);
mermaid.parseError = function (err, hash) {
console.error('Mermaid error: ', err);
};
window.callback = function () {
alert('A callback was triggered');
};
mermaid.initialize({
// theme: 'base',
// handdrawnSeed: 12,
look: 'classic',
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
'elk.nodePlacement.strategy': 'SIMPLE',
// 'elk.nodePlacement.strategy': 'LAYERED',
// 'elk.mergeEdges': true,
// layout: 'dagre',
layout: 'elk',
// layout: 'fixed',
// htmlLabels: false,
flowchart: { titleTopMargin: 10, padding: 8 },
// fontFamily: 'Caveat',
fontFamily: 'Kalam',
// fontFamily: 'courier',
sequence: {
actorFontFamily: 'courier',
noteFontFamily: 'courier',
messageFontFamily: 'courier',
},
fontSize: 12,
logLevel: 0,
securityLevel: 'loose',
});
function callback() {
alert('It worked');
}
mermaid.parseError = function (err, hash) {
console.error('In parse error:');
console.error(err);
};
</script>
</body>
</html>
<script type="module">
import mermaid from './mermaid.esm.mjs';
import { layouts } from './mermaid-layout-elk.esm.mjs';
mermaid.registerLayoutLoaders(layouts);
mermaid.parseError = function (err, hash) {
console.error('Mermaid error: ', err);
};
window.callback = function () {
alert('A callback was triggered');
};
mermaid.initialize({
// theme: 'base',
// handdrawnSeed: 12,
look: 'classic',
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
'elk.nodePlacement.strategy': 'SIMPLE',
// 'elk.nodePlacement.strategy': 'LAYERED',
// 'elk.mergeEdges': true,
// layout: 'dagre',
layout: 'elk',
// layout: 'fixed',
// htmlLabels: false,
flowchart: { titleTopMargin: 10, padding: 8 },
// fontFamily: 'Caveat',
fontFamily: 'Kalam',
// fontFamily: 'courier',
sequence: {
actorFontFamily: 'courier',
noteFontFamily: 'courier',
messageFontFamily: 'courier',
},
fontSize: 12,
logLevel: 0,
securityLevel: 'loose',
});
function callback() {
alert('It worked');
}
mermaid.parseError = function (err, hash) {
console.error('In parse error:');
console.error(err);
};
</script>
</body>
</html>

View File

@ -63,12 +63,18 @@
<body>
<pre id="diagram4" class="mermaid">
flowchart
A@{ shape: titledCylinder, label: "title" }@ --> B@{ shape: titledCylinder, label: "title B" }@
C@{ shape: titledCylinder, label: "title with very long text but on single line" }@ --> D@{ shape: titledCylinder, label: "title \n with \n multiple \n lines \n of n text" }@
A --> D
A
B@{ shape: multiRect, label: "title aduwab whgdawhbd wajhdbawj" }@
F@{ shape: multiRect, label: "title " }@
G@{ shape: multiRect, label: "title \n duawd \n duawd \n duawd \n duawd" }@
C
D
E
C -->B
B --> D
B --> E
F --> A
A --> F
</pre
>

View File

@ -115,7 +115,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram2" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
stateDiagram-v2
stateId
@ -123,7 +123,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram3" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
stateDiagram-v2
stateId
@ -131,7 +131,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram4" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
stateDiagram-v2
stateId
@ -162,21 +162,21 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram2" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
stateDiagram-v2
state "This is a state description" as s3
</pre>
</td>
<td>
<pre id="diagram3" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
stateDiagram-v2
state "This is a state description" as s4
</pre>
</td>
<td>
<pre id="diagram4" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
stateDiagram-v2
state "This is a state description" as s5
</pre>
@ -206,7 +206,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram2" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
stateDiagram-v2
s22 : This is a state description
@ -214,7 +214,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram3" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
stateDiagram-v2
s23 : This is a state description
@ -222,7 +222,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram4" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
stateDiagram-v2
s24 : This is a state description
@ -258,7 +258,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram2" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
stateDiagram-v2
s41 --> s42
@ -268,7 +268,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram3" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
stateDiagram-v2
s51 --> s52
@ -277,7 +277,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram4" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
stateDiagram-v2
s61 --> s62
@ -316,7 +316,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram2" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
stateDiagram-v2
a3 --> a4: A transition
@ -326,7 +326,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram3" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
stateDiagram-v2
a5 --> a6: A transition
@ -335,7 +335,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram4" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
stateDiagram-v2
a7 --> a8: A transition
@ -376,7 +376,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram2" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
stateDiagram-v2
[*] --> test
@ -387,7 +387,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram3" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
stateDiagram-v2
[*] --> test
test --> [*]
@ -397,7 +397,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram4" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
stateDiagram-v2
[*] --> test
test --> [*]
@ -445,7 +445,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram2" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
stateDiagram-v2
[*] --> First
@ -459,7 +459,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram3" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
stateDiagram-v2
[*] --> First
state First {
@ -472,7 +472,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram4" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
stateDiagram-v2
[*] --> First
state First {
@ -547,7 +547,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram2" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
stateDiagram-v2
[*] --> Level1
@ -572,7 +572,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram3" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
stateDiagram-v2
[*] --> Level1
@ -595,7 +595,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram4" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
stateDiagram-v2
[*] --> Level1
@ -676,7 +676,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram2" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
stateDiagram-v2
[*] --> B1
@ -699,7 +699,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram3" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
stateDiagram-v2
[*] --> B1
B1 --> B2
@ -722,7 +722,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram4" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
stateDiagram-v2
[*] --> B1
B1 --> B2
@ -784,7 +784,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram2" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
stateDiagram-v2
state if_state <<choice>>
@ -796,7 +796,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram3" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
stateDiagram-v2
state if_state <<choice>>
[*] --> IsPositive
@ -807,7 +807,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram4" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
stateDiagram-v2
state if_state <<choice>>
[*] --> IsPositive
@ -865,7 +865,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram2" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
stateDiagram-v2
state fork_state <<fork>>
[*] --> fork_state
@ -882,7 +882,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram3" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
stateDiagram-v2
state fork_state <<fork>>
[*] --> fork_state
@ -899,7 +899,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram4" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
stateDiagram-v2
state fork_state <<fork>>
[*] --> fork_state
@ -955,7 +955,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram2" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
stateDiagram-v2
TN3: The state with a note
note right of TN3
@ -968,7 +968,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram3" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
stateDiagram-v2
TN5: The state with a note
note right of TN5
@ -982,7 +982,7 @@ stateDiagram-v2
</td>
<td>
<pre id="diagram4" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
stateDiagram-v2
TN7: The state with a note
note right of TN7
@ -1052,7 +1052,7 @@ state Active {
</td>
<td>
<pre id="diagram2" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
stateDiagram-v2
[*] --> Active
@ -1073,7 +1073,7 @@ state Active {
</td>
<td>
<pre id="diagram3" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
stateDiagram-v2
[*] --> Active
@ -1095,7 +1095,7 @@ state Active {
</td>
<td>
<pre id="diagram4" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
stateDiagram-v2
[*] --> Active
@ -1159,7 +1159,7 @@ direction LR
</td>
<td>
<pre id="diagram2" class="mermaid">
%%{init: {"look": "handdrawn"} }%%
%%{init: {"look": "handDrawn"} }%%
stateDiagram-v2
direction LR
[*] --> D1
@ -1174,7 +1174,7 @@ direction LR
</td>
<td>
<pre id="diagram3" class="mermaid">
%%{init: {"handdrawn": false, "layout": "elk"} }%%
%%{init: {"handDrawn": false, "layout": "elk"} }%%
stateDiagram-v2
direction LR
[*] --> D1
@ -1189,7 +1189,7 @@ direction LR
</td>
<td>
<pre id="diagram4" class="mermaid">
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
%%{init: {"look": "handDrawn", "layout": "elk"} }%%
stateDiagram-v2
direction LR
[*] --> D1
@ -1229,7 +1229,7 @@ direction LR
};
mermaid.initialize({
handdrawn: false,
handDrawn: false,
mergeEdges: true,
layout: 'dagre',
flowchart: { titleTopMargin: 10 },
@ -1254,7 +1254,7 @@ direction LR
let coll = document.getElementsByClassName("collapsible");
for (const element of coll) {
element.addEventListener("click", function () {
element.addEventListener("click", function () {
this.classList.toggle("active");
let content = this.nextElementSibling;
if (content.style.maxHeight) {

View File

@ -9,7 +9,6 @@ function b64ToUtf8(str) {
// Adds a rendered flag to window when rendering is done, so cypress can wait for it.
function markRendered() {
console.log('Done rendering');
if (window.Cypress) {
window.rendered = true;
}

View File

@ -210,11 +210,11 @@ If set to true, ignores legacyMathML.
---
### handdrawnSeed
### handDrawnSeed
`Optional` **handdrawnSeed**: `number`
`Optional` **handDrawnSeed**: `number`
Defines the seed to be used when using handdrawn look. This is important for the automated tests as they will always find differences without the seed. The default value is 0 which gives a random seed.
Defines the seed to be used when using handDrawn look. This is important for the automated tests as they will always find differences without the seed. The default value is 0 which gives a random seed.
#### Defined in
@ -283,7 +283,7 @@ This option decides the amount of logging to be used by mermaid.
### look
`Optional` **look**: `"classic"` | `"handdrawn"`
`Optional` **look**: `"classic"` | `"handDrawn"`
Defines which main look to use for the diagram.
@ -460,7 +460,7 @@ This is useful when you want to control how to handle syntax errors in your appl
### theme
`Optional` **theme**: `"default"` | `"forest"` | `"dark"` | `"neutral"` | `"null"`
`Optional` **theme**: `"default"` | `"base"` | `"dark"` | `"forest"` | `"neutral"` | `"null"`
Theme, the CSS style sheet.
You may also use `themeCSS` to override this value.

View File

@ -98,7 +98,7 @@
"eslint-plugin-markdown": "^5.0.0",
"eslint-plugin-no-only-tests": "^3.1.0",
"eslint-plugin-tsdoc": "^0.3.0",
"eslint-plugin-unicorn": "^54.0.0",
"eslint-plugin-unicorn": "^55.0.0",
"express": "^4.19.1",
"globals": "^15.4.0",
"globby": "^14.0.1",

View File

@ -620,7 +620,7 @@ export const render = async (data4Layout: LayoutData, svg, element, algorithm) =
}
if (endNode.isGroup) {
const bbox = endNode.domId.node().getBBox();
ew = Math.max(startNode.width, endNode.labels[0].width + endNode.padding);
ew = Math.max(endNode.width, endNode.labels[0].width + endNode.padding);
log.debug(
'UIO width',
@ -638,10 +638,6 @@ export const render = async (data4Layout: LayoutData, svg, element, algorithm) =
x: startNode.x + startNode.width / 2 + offset.x,
y: startNode.y + startNode.height / 2 + offset.y,
});
edge.points.push({
x: endNode.x + endNode.width / 2 + offset.x,
y: endNode.y + endNode.height / 2 + offset.y,
});
}
if (endNode.shape === 'diamond') {
edge.points.push({
@ -665,8 +661,8 @@ export const render = async (data4Layout: LayoutData, svg, element, algorithm) =
edge.points = cutPathAtIntersect(
edge.points,
{
x: endNode.x + ew / 2 + offset.x,
y: endNode.y + endNode.height / 2 + offset.y,
x: endNode.x + ew / 2 + endNode.offset.x,
y: endNode.y + endNode.height / 2 + endNode.offset.y,
width: ew,
height: endNode.height,
padding: endNode.padding,

View File

@ -61,19 +61,19 @@ export interface MermaidConfig {
* You may also use `themeCSS` to override this value.
*
*/
theme?: 'default' | 'forest' | 'dark' | 'neutral' | 'null';
theme?: 'default' | 'base' | 'dark' | 'forest' | 'neutral' | 'null';
themeVariables?: any;
themeCSS?: string;
/**
* Defines which main look to use for the diagram.
*
*/
look?: 'classic' | 'handdrawn';
look?: 'classic' | 'handDrawn';
/**
* Defines the seed to be used when using handdrawn look. This is important for the automated tests as they will always find differences without the seed. The default value is 0 which gives a random seed.
* Defines the seed to be used when using handDrawn look. This is important for the automated tests as they will always find differences without the seed. The default value is 0 which gives a random seed.
*
*/
handdrawnSeed?: number;
handDrawnSeed?: number;
/**
* Defines which layout algorithm to use for rendering the diagram.
*

View File

@ -8,13 +8,6 @@ import type { BlockDB } from './blockDB.js';
import { layout } from './layout.js';
import { calculateBlockSizes, insertBlocks, insertEdges } from './renderHelpers.js';
/**
* Returns the all the styles from classDef statements in the graph definition.
*
* @param text - The text with the classes
* @param diagObj - The diagram object
* @returns ClassDef - The styles
*/
export const getClasses = function (text: any, diagObj: any) {
return diagObj.db.getClasses();
};
@ -45,8 +38,6 @@ export const draw = async function (
const markers = ['point', 'circle', 'cross'];
// Add the marker definitions to the svg as marker tags
// insertMarkers(svg, markers, diagObj.type, diagObj.arrowMarkerAbsolute);
// insertMarkers(svg, markers, diagObj.type, true);
insertMarkers(svg, markers, diagObj.type, id);
const bl = db.getBlocks();
@ -59,11 +50,7 @@ export const draw = async function (
await insertBlocks(nodes, bl, db);
await insertEdges(nodes, edges, blArr, db, id);
// log.debug('Here', bl);
// Establish svg dimensions and get width and height
//
// const bounds2 = nodes.node().getBoundingClientRect();
// Why, oh why ????
if (bounds) {
const bounds2 = bounds;

View File

@ -64,7 +64,7 @@ export const addVertex = function (
props = {},
shapeData: any
) {
console.log('addVertex', id, shapeData);
// console.log('addVertex', id, shapeData);
if (!id || id.trim().length === 0) {
return;
}
@ -124,10 +124,10 @@ export const addVertex = function (
// detect if shapeData contains a newline character
if (!shapeData.includes('\n')) {
console.log('yamlData shapeData has no new lines', shapeData);
// console.log('yamlData shapeData has no new lines', shapeData);
yamlData = '{\n' + shapeData + '\n';
} else {
console.log('yamlData shapeData has new lines', shapeData);
// console.log('yamlData shapeData has new lines', shapeData);
yamlData = shapeData + '\n';
// Find the position of the last } and replace it with a newline
const lastPos = yamlData.lastIndexOf('}');
@ -136,9 +136,9 @@ export const addVertex = function (
}
}
console.log('yamlData', yamlData);
// console.log('yamlData', yamlData);
const doc = yaml.load(yamlData, { schema: yaml.JSON_SCHEMA });
console.log('yamlData doc', doc);
// console.log('yamlData doc', doc);
if (doc?.shape) {
//check if shape has a trailing `,` and remove it
if (doc.shape.endsWith(',')) {

View File

@ -1,7 +1,7 @@
// @ts-ignore: JISON doesn't support types
import flowParser from './parser/flow.jison';
import flowDb from './flowDb.js';
import flowRendererV3 from './flowRenderer-v3-unified.js';
import renderer from './flowRenderer-v3-unified.js';
import flowStyles from './styles.js';
import type { MermaidConfig } from '../../config.type.js';
import { setConfig } from '../../diagram-api/diagramAPI.js';
@ -9,7 +9,7 @@ import { setConfig } from '../../diagram-api/diagramAPI.js';
export const diagram = {
parser: flowParser,
db: flowDb,
renderer: flowRendererV3,
renderer,
styles: flowStyles,
init: (cnf: MermaidConfig) => {
if (!cnf.flowchart) {

View File

@ -1,24 +1,23 @@
// @ts-ignore: JISON doesn't support types
import flowParser from './parser/flow.jison';
import flowDb from './flowDb.js';
import flowRenderer from './flowRenderer.js';
import flowRendererV2 from './flowRenderer-v2.js';
import renderer from './flowRenderer-v3-unified.js';
import flowStyles from './styles.js';
import type { MermaidConfig } from '../../config.type.js';
import { setConfig } from '../../diagram-api/diagramAPI.js';
export const diagram = {
parser: flowParser,
db: flowDb,
renderer: flowRendererV2,
renderer,
styles: flowStyles,
init: (cnf: MermaidConfig) => {
if (!cnf.flowchart) {
cnf.flowchart = {};
}
// TODO, broken as of 2022-09-14 (13809b50251845475e6dca65cc395761be38fbd2)
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
flowRenderer.setConf(cnf.flowchart);
setConfig({ flowchart: { arrowMarkerAbsolute: cnf.arrowMarkerAbsolute } });
flowDb.clear();
flowDb.setGen('gen-1');
flowDb.setGen('gen-2');
},
};

View File

@ -1,515 +0,0 @@
import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
import { select, curveLinear, selectAll } from 'd3';
import { getConfig } from '../../diagram-api/diagramAPI.js';
import utils, { getEdgeId } from '../../utils.js';
import { render } from '../../dagre-wrapper/index.js';
import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js';
import { log } from '../../logger.js';
import common, { evaluate, renderKatex } from '../common/common.js';
import { interpolateToCurve, getStylesFromArray } from '../../utils.js';
import { setupGraphViewbox } from '../../setupGraphViewbox.js';
const conf = {};
export const setConf = function (cnf) {
const keys = Object.keys(cnf);
for (const key of keys) {
conf[key] = cnf[key];
}
};
/**
* Function that adds the vertices found during parsing to the graph to be rendered.
*
* @param vert Object containing the vertices.
* @param g The graph that is to be drawn.
* @param svgId
* @param root
* @param doc
* @param diagObj
*/
export const addVertices = async function (vert, g, svgId, root, doc, diagObj) {
const svg = root.select(`[id="${svgId}"]`);
const keys = vert.keys();
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
for (const id of keys) {
const vertex = vert.get(id);
/**
* Variable for storing the classes for the vertex
*
* @type {string}
*/
let classStr = 'default';
if (vertex.classes.length > 0) {
classStr = vertex.classes.join(' ');
}
classStr = classStr + ' flowchart-label';
const styles = getStylesFromArray(vertex.styles);
// Use vertex id as text in the box if no text is provided by the graph definition
let vertexText = vertex.text !== undefined ? vertex.text : vertex.id;
// We create a SVG label, either by delegating to addHtmlLabel or manually
let vertexNode;
log.info('vertex', vertex, vertex.labelType);
if (vertex.labelType === 'markdown') {
log.info('vertex', vertex, vertex.labelType);
} else {
if (evaluate(getConfig().flowchart.htmlLabels)) {
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
const node = {
label: vertexText,
};
vertexNode = addHtmlLabel(svg, node).node();
vertexNode.parentNode.removeChild(vertexNode);
} else {
const svgLabel = doc.createElementNS('http://www.w3.org/2000/svg', 'text');
svgLabel.setAttribute('style', styles.labelStyle.replace('color:', 'fill:'));
const rows = vertexText.split(common.lineBreakRegex);
for (const row of rows) {
const tspan = doc.createElementNS('http://www.w3.org/2000/svg', 'tspan');
tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
tspan.setAttribute('dy', '1em');
tspan.setAttribute('x', '1');
tspan.textContent = row;
svgLabel.appendChild(tspan);
}
vertexNode = svgLabel;
}
}
let radius = 0;
let _shape = '';
// Set the shape based parameters
switch (vertex.type) {
case 'round':
radius = 5;
_shape = 'rect';
break;
case 'square':
_shape = 'rect';
break;
case 'diamond':
_shape = 'question';
break;
case 'hexagon':
_shape = 'hexagon';
break;
case 'odd':
_shape = 'rect_left_inv_arrow';
break;
case 'lean_right':
_shape = 'lean_right';
break;
case 'lean_left':
_shape = 'lean_left';
break;
case 'trapezoid':
_shape = 'trapezoid';
break;
case 'inv_trapezoid':
_shape = 'inv_trapezoid';
break;
case 'odd_right':
_shape = 'rect_left_inv_arrow';
break;
case 'circle':
_shape = 'circle';
break;
case 'ellipse':
_shape = 'ellipse';
break;
case 'stadium':
_shape = 'stadium';
break;
case 'subroutine':
_shape = 'subroutine';
break;
case 'cylinder':
_shape = 'cylinder';
break;
case 'group':
_shape = 'rect';
break;
case 'doublecircle':
_shape = 'doublecircle';
break;
default:
_shape = 'rect';
}
const labelText = await renderKatex(vertexText, getConfig());
// Add the node
g.setNode(vertex.id, {
labelStyle: styles.labelStyle,
shape: _shape,
labelText,
labelType: vertex.labelType,
rx: radius,
ry: radius,
class: classStr,
style: styles.style,
id: vertex.id,
link: vertex.link,
linkTarget: vertex.linkTarget,
tooltip: diagObj.db.getTooltip(vertex.id) || '',
domId: diagObj.db.lookUpDomId(vertex.id),
haveCallback: vertex.haveCallback,
width: vertex.type === 'group' ? 500 : undefined,
dir: vertex.dir,
type: vertex.type,
props: vertex.props,
padding: getConfig().flowchart.padding,
});
log.info('setNode', {
labelStyle: styles.labelStyle,
labelType: vertex.labelType,
shape: _shape,
labelText,
rx: radius,
ry: radius,
class: classStr,
style: styles.style,
id: vertex.id,
domId: diagObj.db.lookUpDomId(vertex.id),
width: vertex.type === 'group' ? 500 : undefined,
type: vertex.type,
dir: vertex.dir,
props: vertex.props,
padding: getConfig().flowchart.padding,
});
}
};
/**
* Add edges to graph based on parsed graph definition
*
* @param {object} edges The edges to add to the graph
* @param {object} g The graph object
*/
export const addEdges = async function (edges, g) {
log.info('abc78 edges = ', edges);
let cnt = 0;
let linkIdCnt = {};
let defaultStyle;
let defaultLabelStyle;
if (edges.defaultStyle !== undefined) {
const defaultStyles = getStylesFromArray(edges.defaultStyle);
defaultStyle = defaultStyles.style;
defaultLabelStyle = defaultStyles.labelStyle;
}
for (const edge of edges) {
cnt++;
// Identify Link
const linkIdBase = getEdgeId(edge.start, edge.end, {
counter: cnt,
prefix: 'L',
});
// count the links from+to the same node to give unique id
if (linkIdCnt[linkIdBase] === undefined) {
linkIdCnt[linkIdBase] = 0;
log.info('abc78 new entry', linkIdBase, linkIdCnt[linkIdBase]);
} else {
linkIdCnt[linkIdBase]++;
log.info('abc78 new entry', linkIdBase, linkIdCnt[linkIdBase]);
}
let linkId = `${linkIdBase}_${linkIdCnt[linkIdBase]}`;
log.info('abc78 new link id to be used is', linkIdBase, linkId, linkIdCnt[linkIdBase]);
const linkNameStart = 'LS-' + edge.start;
const linkNameEnd = 'LE-' + edge.end;
const edgeData = { style: '', labelStyle: '' };
edgeData.minlen = edge.length || 1;
//edgeData.id = 'id' + cnt;
// Set link type for rendering
if (edge.type === 'arrow_open') {
edgeData.arrowhead = 'none';
} else {
edgeData.arrowhead = 'normal';
}
// Check of arrow types, placed here in order not to break old rendering
edgeData.arrowTypeStart = 'arrow_open';
edgeData.arrowTypeEnd = 'arrow_open';
/* eslint-disable no-fallthrough */
switch (edge.type) {
case 'double_arrow_cross':
edgeData.arrowTypeStart = 'arrow_cross';
case 'arrow_cross':
edgeData.arrowTypeEnd = 'arrow_cross';
break;
case 'double_arrow_point':
edgeData.arrowTypeStart = 'arrow_point';
case 'arrow_point':
edgeData.arrowTypeEnd = 'arrow_point';
break;
case 'double_arrow_circle':
edgeData.arrowTypeStart = 'arrow_circle';
case 'arrow_circle':
edgeData.arrowTypeEnd = 'arrow_circle';
break;
}
let style = '';
let labelStyle = '';
switch (edge.stroke) {
case 'normal':
style = 'fill:none;';
if (defaultStyle !== undefined) {
style = defaultStyle;
}
if (defaultLabelStyle !== undefined) {
labelStyle = defaultLabelStyle;
}
edgeData.thickness = 'normal';
edgeData.pattern = 'solid';
break;
case 'dotted':
edgeData.thickness = 'normal';
edgeData.pattern = 'dotted';
edgeData.style = 'fill:none;stroke-width:2px;stroke-dasharray:3;';
break;
case 'thick':
edgeData.thickness = 'thick';
edgeData.pattern = 'solid';
edgeData.style = 'stroke-width: 3.5px;fill:none;';
break;
case 'invisible':
edgeData.thickness = 'invisible';
edgeData.pattern = 'solid';
edgeData.style = 'stroke-width: 0;fill:none;';
break;
}
if (edge.style !== undefined) {
const styles = getStylesFromArray(edge.style);
style = styles.style;
labelStyle = styles.labelStyle;
}
edgeData.style = edgeData.style += style;
edgeData.labelStyle = edgeData.labelStyle += labelStyle;
if (edge.interpolate !== undefined) {
edgeData.curve = interpolateToCurve(edge.interpolate, curveLinear);
} else if (edges.defaultInterpolate !== undefined) {
edgeData.curve = interpolateToCurve(edges.defaultInterpolate, curveLinear);
} else {
edgeData.curve = interpolateToCurve(conf.curve, curveLinear);
}
if (edge.text === undefined) {
if (edge.style !== undefined) {
edgeData.arrowheadStyle = 'fill: #333';
}
} else {
edgeData.arrowheadStyle = 'fill: #333';
edgeData.labelpos = 'c';
}
edgeData.labelType = edge.labelType;
edgeData.label = await renderKatex(edge.text.replace(common.lineBreakRegex, '\n'), getConfig());
if (edge.style === undefined) {
edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none;';
}
edgeData.labelStyle = edgeData.labelStyle.replace('color:', 'fill:');
edgeData.id = linkId;
edgeData.classes = 'flowchart-link ' + linkNameStart + ' ' + linkNameEnd;
// Add the edge to the graph
g.setEdge(edge.start, edge.end, edgeData, cnt);
}
};
/**
* Returns the all the styles from classDef statements in the graph definition.
*
* @param text
* @param diagObj
* @returns {Map<string, import('../../diagram-api/types.js').DiagramStyleClassDef>} ClassDef styles
*/
export const getClasses = function (text, diagObj) {
return diagObj.db.getClasses();
};
/**
* Draws a flowchart in the tag with id: id based on the graph definition in text.
*
* @param text
* @param id
* @param _version
* @param diagObj
*/
export const draw = async function (text, id, _version, diagObj) {
log.info('Drawing flowchart');
// Fetch the default direction, use TD if none was found
let dir = diagObj.db.getDirection();
if (dir === undefined) {
dir = 'TD';
}
const { securityLevel, flowchart: conf } = getConfig();
const nodeSpacing = conf.nodeSpacing ?? 50;
const rankSpacing = conf.rankSpacing ?? 50;
// Handle root and document for when rendering in sandbox mode
let sandboxElement;
if (securityLevel === 'sandbox') {
sandboxElement = select('#i' + id);
}
const root =
securityLevel === 'sandbox'
? select(sandboxElement.nodes()[0].contentDocument.body)
: select('body');
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
// Create the input mermaid.graph
const g = new graphlib.Graph({
multigraph: true,
compound: true,
})
.setGraph({
rankdir: dir,
nodesep: nodeSpacing,
ranksep: rankSpacing,
marginx: 0,
marginy: 0,
})
.setDefaultEdgeLabel(function () {
return {};
});
let subG;
const subGraphs = diagObj.db.getSubGraphs();
log.info('Subgraphs - ', subGraphs);
for (let i = subGraphs.length - 1; i >= 0; i--) {
subG = subGraphs[i];
log.info('Subgraph - ', subG);
diagObj.db.addVertex(
subG.id,
{ text: subG.title, type: subG.labelType },
'group',
undefined,
subG.classes,
subG.dir
);
}
// Fetch the vertices/nodes and edges/links from the parsed graph definition
const vert = diagObj.db.getVertices();
const edges = diagObj.db.getEdges();
log.info('Edges', edges);
let i = 0;
for (i = subGraphs.length - 1; i >= 0; i--) {
subG = subGraphs[i];
selectAll('cluster').append('text');
for (const node of subG.nodes) {
log.info('Setting up subgraphs', node, subG.id);
g.setParent(node, subG.id);
}
}
await addVertices(vert, g, id, root, doc, diagObj);
await addEdges(edges, g, diagObj);
// Add custom shapes
// flowChartShapes.addToRenderV2(addShape);
// Set up an SVG group so that we can translate the final graph.
const svg = root.select(`[id="${id}"]`);
// Run the renderer. This is what draws the final graph.
const element = root.select('#' + id + ' g');
await render(element, g, ['point', 'circle', 'cross'], 'flowchart', id);
utils.insertTitle(svg, 'flowchartTitleText', conf.titleTopMargin, diagObj.db.getDiagramTitle());
setupGraphViewbox(g, svg, conf.diagramPadding, conf.useMaxWidth);
// Index nodes
diagObj.db.indexNodes('subGraph' + i);
// Add label rects for non html labels
if (!conf.htmlLabels) {
const labels = doc.querySelectorAll('[id="' + id + '"] .edgeLabel .label');
for (const label of labels) {
// Get dimensions of label
const dim = label.getBBox();
const rect = doc.createElementNS('http://www.w3.org/2000/svg', 'rect');
rect.setAttribute('rx', 0);
rect.setAttribute('ry', 0);
rect.setAttribute('width', dim.width);
rect.setAttribute('height', dim.height);
label.insertBefore(rect, label.firstChild);
}
}
// If node has a link, wrap it in an anchor SVG object.
const keys = [...vert.keys()];
keys.forEach((key) => {
const vertex = vert.get(key);
if (vertex.link) {
const node = select('#' + id + ' [id="' + key + '"]');
if (node) {
const link = doc.createElementNS('http://www.w3.org/2000/svg', 'a');
link.setAttributeNS('http://www.w3.org/2000/svg', 'class', vertex.classes.join(' '));
link.setAttributeNS('http://www.w3.org/2000/svg', 'href', vertex.link);
link.setAttributeNS('http://www.w3.org/2000/svg', 'rel', 'noopener');
if (securityLevel === 'sandbox') {
link.setAttributeNS('http://www.w3.org/2000/svg', 'target', '_top');
} else if (vertex.linkTarget) {
link.setAttributeNS('http://www.w3.org/2000/svg', 'target', vertex.linkTarget);
}
const linkNode = node.insert(function () {
return link;
}, ':first-child');
const shape = node.select('.label-container');
if (shape) {
linkNode.append(function () {
return shape.node();
});
}
const label = node.select('.label');
if (label) {
linkNode.append(function () {
return label.node();
});
}
}
}
});
};
export default {
setConf,
addVertices,
addEdges,
getClasses,
draw,
};

View File

@ -1,150 +0,0 @@
import flowDb from './flowDb.js';
import { parser } from './parser/flow.jison';
import flowRenderer from './flowRenderer.js';
import { addDiagrams } from '../../diagram-api/diagram-orchestration.js';
const diag = {
db: flowDb,
};
addDiagrams();
describe('when using mermaid and ', function () {
describe('when calling addEdges ', function () {
beforeEach(function () {
parser.yy = flowDb;
flowDb.clear();
flowDb.setGen('gen-2');
});
it('should handle edges with text', async () => {
parser.parse('graph TD;A-->|text ex|B;');
flowDb.getVertices();
const edges = flowDb.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B-');
expect(options.arrowhead).toBe('normal');
expect(options.label.match('text ex')).toBeTruthy();
},
};
await flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle edges without text', async function () {
parser.parse('graph TD;A-->B;');
flowDb.getVertices();
const edges = flowDb.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B-');
expect(options.arrowhead).toBe('normal');
},
};
await flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle open-ended edges', async () => {
parser.parse('graph TD;A---B;');
flowDb.getVertices();
const edges = flowDb.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B-');
expect(options.arrowhead).toBe('none');
},
};
await flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle edges with styles defined', async () => {
parser.parse('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;');
flowDb.getVertices();
const edges = flowDb.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B-');
expect(options.arrowhead).toBe('none');
expect(options.style).toBe('stroke:val1;stroke-width:val2;fill:none;');
},
};
await flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle edges with interpolation defined', async () => {
parser.parse('graph TD;A---B; linkStyle 0 interpolate basis');
flowDb.getVertices();
const edges = flowDb.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B-');
expect(options.arrowhead).toBe('none');
expect(options.curve).toBe('basis'); // mocked as string
},
};
await flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle edges with text and styles defined', async () => {
parser.parse('graph TD;A---|the text|B; linkStyle 0 stroke:val1,stroke-width:val2;');
flowDb.getVertices();
const edges = flowDb.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B-');
expect(options.arrowhead).toBe('none');
expect(options.label.match('the text')).toBeTruthy();
expect(options.style).toBe('stroke:val1;stroke-width:val2;fill:none;');
},
};
await flowRenderer.addEdges(edges, mockG, diag);
});
it('should set fill to "none" by default when handling edges', async () => {
parser.parse('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;');
flowDb.getVertices();
const edges = flowDb.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B');
expect(options.arrowhead).toBe('none');
expect(options.style).toBe('stroke:val1;stroke-width:val2;fill:none;');
},
};
await flowRenderer.addEdges(edges, mockG, diag);
});
it('should not set fill to none if fill is set in linkStyle', async () => {
parser.parse('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2,fill:blue;');
flowDb.getVertices();
const edges = flowDb.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B-');
expect(options.arrowhead).toBe('none');
expect(options.style).toBe('stroke:val1;stroke-width:val2;fill:blue;');
},
};
await flowRenderer.addEdges(edges, mockG, diag);
});
});
});

View File

@ -1,503 +0,0 @@
import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
import { select, curveLinear, selectAll } from 'd3';
import { getConfig } from '../../diagram-api/diagramAPI.js';
import { render as Render } from 'dagre-d3-es';
import { applyStyle } from 'dagre-d3-es/src/dagre-js/util.js';
import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js';
import { log } from '../../logger.js';
import common, { evaluate, renderKatex } from '../common/common.js';
import { interpolateToCurve, getStylesFromArray, getEdgeId } from '../../utils.js';
import { setupGraphViewbox } from '../../setupGraphViewbox.js';
import flowChartShapes from './flowChartShapes.js';
import { replaceIconSubstring } from '../../rendering-util/createText.js';
const conf = {};
export const setConf = function (cnf) {
const keys = Object.keys(cnf);
for (const key of keys) {
conf[key] = cnf[key];
}
};
/**
* Function that adds the vertices found in the graph definition to the graph to be rendered.
*
* @param vert Object containing the vertices.
* @param g The graph that is to be drawn.
* @param svgId
* @param root
* @param _doc
* @param diagObj
*/
export const addVertices = async function (vert, g, svgId, root, _doc, diagObj) {
const svg = !root ? select(`[id="${svgId}"]`) : root.select(`[id="${svgId}"]`);
const doc = !_doc ? document : _doc;
const keys = Object.keys(vert);
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
for (const id of keys) {
const vertex = vert[id];
/**
* Variable for storing the classes for the vertex
*
* @type {string}
*/
let classStr = 'default';
if (vertex.classes.length > 0) {
classStr = vertex.classes.join(' ');
}
const styles = getStylesFromArray(vertex.styles);
// Use vertex id as text in the box if no text is provided by the graph definition
let vertexText = vertex.text !== undefined ? vertex.text : vertex.id;
// We create a SVG label, either by delegating to addHtmlLabel or manually
let vertexNode;
if (evaluate(getConfig().flowchart.htmlLabels)) {
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
const replacedVertexText = replaceIconSubstring(vertexText);
const node = {
label: await renderKatex(replacedVertexText, getConfig()),
};
vertexNode = addHtmlLabel(svg, node).node();
vertexNode.parentNode.removeChild(vertexNode);
} else {
const svgLabel = doc.createElementNS('http://www.w3.org/2000/svg', 'text');
svgLabel.setAttribute('style', styles.labelStyle.replace('color:', 'fill:'));
const rows = vertexText.split(common.lineBreakRegex);
for (const row of rows) {
const tspan = doc.createElementNS('http://www.w3.org/2000/svg', 'tspan');
tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
tspan.setAttribute('dy', '1em');
tspan.setAttribute('x', '1');
tspan.textContent = row;
svgLabel.appendChild(tspan);
}
vertexNode = svgLabel;
}
let radius = 0;
let _shape = '';
// Set the shape based parameters
switch (vertex.type) {
case 'round':
radius = 5;
_shape = 'rect';
break;
case 'square':
_shape = 'rect';
break;
case 'diamond':
_shape = 'question';
break;
case 'hexagon':
_shape = 'hexagon';
break;
case 'odd':
_shape = 'rect_left_inv_arrow';
break;
case 'lean_right':
_shape = 'lean_right';
break;
case 'lean_left':
_shape = 'lean_left';
break;
case 'trapezoid':
_shape = 'trapezoid';
break;
case 'inv_trapezoid':
_shape = 'inv_trapezoid';
break;
case 'odd_right':
_shape = 'rect_left_inv_arrow';
break;
case 'circle':
_shape = 'circle';
break;
case 'ellipse':
_shape = 'ellipse';
break;
case 'stadium':
_shape = 'stadium';
break;
case 'subroutine':
_shape = 'subroutine';
break;
case 'cylinder':
_shape = 'cylinder';
break;
case 'group':
_shape = 'rect';
break;
default:
_shape = 'rect';
}
// Add the node
log.warn('Adding node', vertex.id, vertex.domId);
g.setNode(diagObj.db.lookUpDomId(vertex.id), {
labelType: 'svg',
labelStyle: styles.labelStyle,
shape: _shape,
label: vertexNode,
rx: radius,
ry: radius,
class: classStr,
style: styles.style,
id: diagObj.db.lookUpDomId(vertex.id),
});
}
};
/**
* Add edges to graph based on parsed graph definition
*
* @param {object} edges The edges to add to the graph
* @param {object} g The graph object
* @param diagObj
*/
export const addEdges = async function (edges, g, diagObj) {
let cnt = 0;
let defaultStyle;
let defaultLabelStyle;
if (edges.defaultStyle !== undefined) {
const defaultStyles = getStylesFromArray(edges.defaultStyle);
defaultStyle = defaultStyles.style;
defaultLabelStyle = defaultStyles.labelStyle;
}
for (const edge of edges) {
cnt++;
// Identify Link
const linkId = getEdgeId(edge.start, edge.end, {
counter: cnt,
prefix: 'L',
});
const linkNameStart = 'LS-' + edge.start;
const linkNameEnd = 'LE-' + edge.end;
const edgeData = {};
// Set link type for rendering
if (edge.type === 'arrow_open') {
edgeData.arrowhead = 'none';
} else {
edgeData.arrowhead = 'normal';
}
let style = '';
let labelStyle = '';
if (edge.style !== undefined) {
const styles = getStylesFromArray(edge.style);
style = styles.style;
labelStyle = styles.labelStyle;
} else {
switch (edge.stroke) {
case 'normal':
style = 'fill:none';
if (defaultStyle !== undefined) {
style = defaultStyle;
}
if (defaultLabelStyle !== undefined) {
labelStyle = defaultLabelStyle;
}
break;
case 'dotted':
style = 'fill:none;stroke-width:2px;stroke-dasharray:3;';
break;
case 'thick':
style = ' stroke-width: 3.5px;fill:none';
break;
}
}
edgeData.style = style;
edgeData.labelStyle = labelStyle;
if (edge.interpolate !== undefined) {
edgeData.curve = interpolateToCurve(edge.interpolate, curveLinear);
} else if (edges.defaultInterpolate !== undefined) {
edgeData.curve = interpolateToCurve(edges.defaultInterpolate, curveLinear);
} else {
edgeData.curve = interpolateToCurve(conf.curve, curveLinear);
}
if (edge.text === undefined) {
if (edge.style !== undefined) {
edgeData.arrowheadStyle = 'fill: #333';
}
} else {
edgeData.arrowheadStyle = 'fill: #333';
edgeData.labelpos = 'c';
if (evaluate(getConfig().flowchart.htmlLabels)) {
edgeData.labelType = 'html';
edgeData.label = `<span id="L-${linkId}" class="edgeLabel L-${linkNameStart}' L-${linkNameEnd}" style="${
edgeData.labelStyle
}">${await renderKatex(replaceIconSubstring(edge.text), getConfig())}</span>`;
} else {
edgeData.labelType = 'text';
edgeData.label = edge.text.replace(common.lineBreakRegex, '\n');
if (edge.style === undefined) {
edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none';
}
edgeData.labelStyle = edgeData.labelStyle.replace('color:', 'fill:');
}
}
edgeData.id = linkId;
edgeData.class = linkNameStart + ' ' + linkNameEnd;
edgeData.minlen = edge.length || 1;
// Add the edge to the graph
g.setEdge(diagObj.db.lookUpDomId(edge.start), diagObj.db.lookUpDomId(edge.end), edgeData, cnt);
}
};
/**
* Returns the all the styles from classDef statements in the graph definition.
*
* @param text
* @param diagObj
* @returns {Map<string, import('../../diagram-api/types.js').DiagramStyleClassDef>} ClassDef styles
*/
export const getClasses = function (text, diagObj) {
log.info('Extracting classes');
return diagObj.db.getClasses();
};
/**
* Draws a flowchart in the tag with id: id based on the graph definition in text.
*
* @param text
* @param id
* @param _version
* @param diagObj
*/
export const draw = async function (text, id, _version, diagObj) {
log.info('Drawing flowchart');
const { securityLevel, flowchart: conf } = getConfig();
let sandboxElement;
if (securityLevel === 'sandbox') {
sandboxElement = select('#i' + id);
}
const root =
securityLevel === 'sandbox'
? select(sandboxElement.nodes()[0].contentDocument.body)
: select('body');
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
// Fetch the default direction, use TD if none was found
let dir = diagObj.db.getDirection();
if (dir === undefined) {
dir = 'TD';
}
const nodeSpacing = conf.nodeSpacing ?? 50;
const rankSpacing = conf.rankSpacing ?? 50;
// Create the input mermaid.graph
const g = new graphlib.Graph({
multigraph: true,
compound: true,
})
.setGraph({
rankdir: dir,
nodesep: nodeSpacing,
ranksep: rankSpacing,
marginx: 8,
marginy: 8,
})
.setDefaultEdgeLabel(function () {
return {};
});
let subG;
const subGraphs = diagObj.db.getSubGraphs();
for (let i = subGraphs.length - 1; i >= 0; i--) {
subG = subGraphs[i];
diagObj.db.addVertex(subG.id, subG.title, 'group', undefined, subG.classes);
}
// Fetch the vertices/nodes and edges/links from the parsed graph definition
const vert = diagObj.db.getVertices();
log.warn('Get vertices', vert);
const edges = diagObj.db.getEdges();
let i = 0;
for (i = subGraphs.length - 1; i >= 0; i--) {
subG = subGraphs[i];
selectAll('cluster').append('text');
for (const node of subG.nodes) {
log.warn(
'Setting subgraph',
node,
diagObj.db.lookUpDomId(node),
diagObj.db.lookUpDomId(subG.id)
);
g.setParent(diagObj.db.lookUpDomId(node), diagObj.db.lookUpDomId(subG.id));
}
}
await addVertices(vert, g, id, root, doc, diagObj);
await addEdges(edges, g, diagObj);
// Create the renderer
const render = new Render();
// Add custom shapes
flowChartShapes.addToRender(render);
// Add our custom arrow - an empty arrowhead
render.arrows().none = function normal(parent, id, edge, type) {
const marker = parent
.append('marker')
.attr('id', id)
.attr('viewBox', '0 0 10 10')
.attr('refX', 9)
.attr('refY', 5)
.attr('markerUnits', 'strokeWidth')
.attr('markerWidth', 8)
.attr('markerHeight', 6)
.attr('orient', 'auto');
const path = marker.append('path').attr('d', 'M 0 0 L 0 0 L 0 0 z');
applyStyle(path, edge[type + 'Style']);
};
// Override normal arrowhead defined in d3. Remove style & add class to allow css styling.
render.arrows().normal = function normal(parent, id) {
const marker = parent
.append('marker')
.attr('id', id)
.attr('viewBox', '0 0 10 10')
.attr('refX', 9)
.attr('refY', 5)
.attr('markerUnits', 'strokeWidth')
.attr('markerWidth', 8)
.attr('markerHeight', 6)
.attr('orient', 'auto');
marker
.append('path')
.attr('d', 'M 0 0 L 10 5 L 0 10 z')
.attr('class', 'arrowheadPath')
.style('stroke-width', 1)
.style('stroke-dasharray', '1,0');
};
// Set up an SVG group so that we can translate the final graph.
const svg = root.select(`[id="${id}"]`);
// Run the renderer. This is what draws the final graph.
const element = root.select('#' + id + ' g');
render(element, g);
element.selectAll('g.node').attr('title', function () {
return diagObj.db.getTooltip(this.id);
});
// Index nodes
diagObj.db.indexNodes('subGraph' + i);
// reposition labels
for (i = 0; i < subGraphs.length; i++) {
subG = subGraphs[i];
if (subG.title !== 'undefined') {
const clusterRects = doc.querySelectorAll(
'#' + id + ' [id="' + diagObj.db.lookUpDomId(subG.id) + '"] rect'
);
const clusterEl = doc.querySelectorAll(
'#' + id + ' [id="' + diagObj.db.lookUpDomId(subG.id) + '"]'
);
const xPos = clusterRects[0].x.baseVal.value;
const yPos = clusterRects[0].y.baseVal.value;
const _width = clusterRects[0].width.baseVal.value;
const cluster = select(clusterEl[0]);
const te = cluster.select('.label');
te.attr('transform', `translate(${xPos + _width / 2}, ${yPos + 14})`);
te.attr('id', id + 'Text');
for (const className of subG.classes) {
clusterEl[0].classList.add(className);
}
}
}
// Add label rects for non html labels
if (!conf.htmlLabels) {
const labels = doc.querySelectorAll('[id="' + id + '"] .edgeLabel .label');
for (const label of labels) {
// Get dimensions of label
const dim = label.getBBox();
const rect = doc.createElementNS('http://www.w3.org/2000/svg', 'rect');
rect.setAttribute('rx', 0);
rect.setAttribute('ry', 0);
rect.setAttribute('width', dim.width);
rect.setAttribute('height', dim.height);
// rect.setAttribute('style', 'fill:#e8e8e8;');
label.insertBefore(rect, label.firstChild);
}
}
setupGraphViewbox(g, svg, conf.diagramPadding, conf.useMaxWidth);
// If node has a link, wrap it in an anchor SVG object.
const keys = [...vert.keys()];
keys.forEach(function (key) {
const vertex = vert.get(key);
if (vertex.link) {
const node = root.select('#' + id + ' [id="' + diagObj.db.lookUpDomId(key) + '"]');
if (node) {
const link = doc.createElementNS('http://www.w3.org/2000/svg', 'a');
link.setAttributeNS('http://www.w3.org/2000/svg', 'class', vertex.classes.join(' '));
link.setAttributeNS('http://www.w3.org/2000/svg', 'href', vertex.link);
link.setAttributeNS('http://www.w3.org/2000/svg', 'rel', 'noopener');
if (securityLevel === 'sandbox') {
link.setAttributeNS('http://www.w3.org/2000/svg', 'target', '_top');
} else if (vertex.linkTarget) {
link.setAttributeNS('http://www.w3.org/2000/svg', 'target', vertex.linkTarget);
}
const linkNode = node.insert(function () {
return link;
}, ':first-child');
const shape = node.select('.label-container');
if (shape) {
linkNode.append(function () {
return shape.node();
});
}
const label = node.select('.label');
if (label) {
linkNode.append(function () {
return label.node();
});
}
}
}
});
};
export default {
setConf,
addVertices,
addEdges,
getClasses,
draw,
};

View File

@ -1,277 +0,0 @@
/* eslint-disable @typescript-eslint/restrict-template-expressions */
import { addVertices, addEdges } from './flowRenderer.js';
import { setConfig } from '../../diagram-api/diagramAPI.js';
setConfig({
flowchart: {
htmlLabels: false,
},
});
describe('the flowchart renderer', function () {
describe('when adding vertices to a graph', function () {
[
['round', 'rect', 5],
['square', 'rect'],
['diamond', 'question'],
['hexagon', 'hexagon'],
['odd', 'rect_left_inv_arrow'],
['lean_right', 'lean_right'],
['lean_left', 'lean_left'],
['trapezoid', 'trapezoid'],
['inv_trapezoid', 'inv_trapezoid'],
['odd_right', 'rect_left_inv_arrow'],
['circle', 'circle'],
['ellipse', 'ellipse'],
['stadium', 'stadium'],
['subroutine', 'subroutine'],
['cylinder', 'cylinder'],
['group', 'rect'],
].forEach(function ([type, expectedShape, expectedRadios = 0]) {
it(`should add the correct shaped node to the graph for vertex type ${type}`, async function () {
const fakeDiag = {
db: {
lookUpDomId: () => {
return 'my-node-id';
},
},
};
const addedNodes = [];
const mockG = {
setNode: function (id, object) {
addedNodes.push([id, object]);
},
};
await addVertices(
{
v1: {
type,
id: 'my-node-id',
classes: [],
styles: [],
text: 'my vertex text',
},
},
mockG,
'svg-id',
undefined,
undefined,
fakeDiag
);
expect(addedNodes).toHaveLength(1);
expect(addedNodes[0][0]).toEqual('my-node-id');
expect(addedNodes[0][1]).toHaveProperty('id', 'my-node-id');
expect(addedNodes[0][1]).toHaveProperty('labelType', 'svg');
expect(addedNodes[0][1]).toHaveProperty('shape', expectedShape);
expect(addedNodes[0][1]).toHaveProperty('rx', expectedRadios);
expect(addedNodes[0][1]).toHaveProperty('ry', expectedRadios);
});
});
['Multi<br>Line', 'Multi<br/>Line', 'Multi<br />Line', 'Multi<br\t/>Line'].forEach(
function (labelText) {
it('should handle multiline texts with different line breaks', async function () {
const addedNodes = [];
const fakeDiag = {
db: {
lookUpDomId: () => {
return 'my-node-id';
},
},
};
const mockG = {
setNode: function (id, object) {
addedNodes.push([id, object]);
},
};
await addVertices(
{
v1: {
type: 'rect',
id: 'my-node-id',
classes: [],
styles: [],
text: 'Multi<br>Line',
},
},
mockG,
'svg-id',
false,
document,
fakeDiag
);
expect(addedNodes).toHaveLength(1);
expect(addedNodes[0][0]).toEqual('my-node-id');
expect(addedNodes[0][1]).toHaveProperty('id', 'my-node-id');
expect(addedNodes[0][1]).toHaveProperty('labelType', 'svg');
expect(addedNodes[0][1].label).toBeDefined();
expect(addedNodes[0][1].label).toBeDefined(); // <text> node
expect(addedNodes[0][1].label.firstChild.innerHTML).toEqual('Multi'); // <tspan> node, line 1
expect(addedNodes[0][1].label.lastChild.innerHTML).toEqual('Line'); // <tspan> node, line 2
});
}
);
[
[['fill:#fff'], 'fill:#fff;', ''],
[['color:#ccc'], '', 'color:#ccc;'],
[['fill:#fff', 'color:#ccc'], 'fill:#fff;', 'color:#ccc;'],
[
['fill:#fff', 'color:#ccc', 'text-align:center'],
'fill:#fff;',
'color:#ccc;text-align:center;',
],
].forEach(function ([style, expectedStyle, expectedLabelStyle]) {
it(`should add the styles to style and/or labelStyle for style ${style}`, async function () {
const addedNodes = [];
const fakeDiag = {
db: {
lookUpDomId: () => {
return 'my-node-id';
},
},
};
const mockG = {
setNode: function (id, object) {
addedNodes.push([id, object]);
},
};
await addVertices(
{
v1: {
type: 'rect',
id: 'my-node-id',
classes: [],
styles: style,
text: 'my vertex text',
},
},
mockG,
'svg-id',
undefined,
undefined,
fakeDiag
);
expect(addedNodes).toHaveLength(1);
expect(addedNodes[0][0]).toEqual('my-node-id');
expect(addedNodes[0][1]).toHaveProperty('id', 'my-node-id');
expect(addedNodes[0][1]).toHaveProperty('labelType', 'svg');
expect(addedNodes[0][1]).toHaveProperty('style', expectedStyle);
expect(addedNodes[0][1]).toHaveProperty('labelStyle', expectedLabelStyle);
});
});
it(`should add default class to all nodes which do not have another class assigned`, async function () {
const addedNodes = [];
const mockG = {
setNode: function (id, object) {
addedNodes.push([id, object]);
},
};
const fakeDiag = {
db: {
lookUpDomId: () => {
return 'my-node-id';
},
},
};
await addVertices(
{
v1: {
type: 'rect',
id: 'my-node-id',
classes: [],
styles: [],
text: 'my vertex text',
},
v2: {
type: 'rect',
id: 'myNode',
classes: ['myClass'],
styles: [],
text: 'my vertex text',
},
},
mockG,
'svg-id',
undefined,
undefined,
fakeDiag
);
expect(addedNodes).toHaveLength(2);
expect(addedNodes[0][0]).toEqual('my-node-id');
expect(addedNodes[0][1]).toHaveProperty('class', 'default');
expect(addedNodes[1][0]).toEqual('my-node-id');
expect(addedNodes[1][1]).toHaveProperty('class', 'myClass');
});
});
describe('when adding edges to a graph', function () {
it('should handle multiline texts and set centered label position', async function () {
const addedEdges = [];
const fakeDiag = {
db: {
lookUpDomId: () => {
return 'my-node-id';
},
},
};
const mockG = {
setEdge: function (s, e, data, c) {
addedEdges.push(data);
},
};
await addEdges(
[
{ text: 'Multi<br>Line' },
{ text: 'Multi<br/>Line' },
{ text: 'Multi<br />Line' },
{ text: 'Multi<br\t/>Line' },
{ style: ['stroke:DarkGray', 'stroke-width:2px'], text: 'Multi<br>Line' },
{ style: ['stroke:DarkGray', 'stroke-width:2px'], text: 'Multi<br/>Line' },
{ style: ['stroke:DarkGray', 'stroke-width:2px'], text: 'Multi<br />Line' },
{ style: ['stroke:DarkGray', 'stroke-width:2px'], text: 'Multi<br\t/>Line' },
],
mockG,
fakeDiag
);
addedEdges.forEach(function (edge) {
expect(edge).toHaveProperty('label', 'Multi\nLine');
expect(edge).toHaveProperty('labelpos', 'c');
});
});
[
[['stroke:DarkGray'], 'stroke:DarkGray;', ''],
[['color:red'], '', 'fill:red;'],
[['stroke:DarkGray', 'color:red'], 'stroke:DarkGray;', 'fill:red;'],
[
['stroke:DarkGray', 'color:red', 'stroke-width:2px'],
'stroke:DarkGray;stroke-width:2px;',
'fill:red;',
],
].forEach(function ([style, expectedStyle, expectedLabelStyle]) {
it(`should add the styles to style and/or labelStyle for style ${style}`, async function () {
const addedEdges = [];
const fakeDiag = {
db: {
lookUpDomId: () => {
return 'my-node-id';
},
},
};
const mockG = {
setEdge: function (s, e, data, c) {
addedEdges.push(data);
},
};
await addEdges([{ style: style, text: 'styling' }], mockG, fakeDiag);
expect(addedEdges).toHaveLength(1);
expect(addedEdges[0]).toHaveProperty('style', expectedStyle);
expect(addedEdges[0]).toHaveProperty('labelStyle', expectedLabelStyle);
});
});
});
});

View File

@ -18,7 +18,6 @@ describe('when parsing directions', function () {
D@{ shape: rounded }@`);
const data4Layout = flow.parser.yy.getData();
console.log(data4Layout.nodes);
expect(data4Layout.nodes.length).toBe(1);
expect(data4Layout.nodes[0].shape).toEqual('rounded');
expect(data4Layout.nodes[0].label).toEqual('D');
@ -76,7 +75,6 @@ describe('when parsing directions', function () {
`);
const data4Layout = flow.parser.yy.getData();
console.log(data4Layout.edges);
expect(data4Layout.nodes.length).toBe(2);
expect(data4Layout.nodes[0].shape).toEqual('squareRect');
expect(data4Layout.nodes[0].label).toEqual('A');
@ -126,7 +124,6 @@ describe('when parsing directions', function () {
`);
const data4Layout = flow.parser.yy.getData();
console.log(data4Layout.nodes);
expect(data4Layout.nodes.length).toBe(1);
expect(data4Layout.nodes[0].shape).toEqual('diamond');
expect(data4Layout.nodes[0].label).toEqual('This is a label');

View File

@ -59,7 +59,7 @@ const getStyles = (options: FlowChartStyleOptions) =>
stroke: ${options.nodeBorder};
stroke-width: 1px;
}
.node .label text {
.rough-node .label text , .node .label text {
text-anchor: middle;
}
// .flowchart-label .text-outer-tspan {

View File

@ -23,7 +23,7 @@ export interface FlowEdge {
end: string;
interpolate?: string;
type?: string;
stroke?: 'normal' | 'thick' | 'invisible';
stroke?: 'normal' | 'thick' | 'invisible' | 'dotted';
style?: string[];
length?: number;
text: string;

View File

@ -1088,6 +1088,19 @@ export const draw = async function (_text: string, id: string, _version: string,
const { bounds: box } = bounds.getBounds();
if (box.startx === undefined) {
box.startx = 0;
}
if (box.starty === undefined) {
box.starty = 0;
}
if (box.stopx === undefined) {
box.stopx = 0;
}
if (box.stopy === undefined) {
box.stopy = 0;
}
// Make sure the height of the diagram supports long menus.
let boxHeight = box.stopy - box.starty;
if (boxHeight < requiredBoxSize.maxHeight) {

View File

@ -131,12 +131,6 @@ const getDir = (parsedItem, defaultDir = DEFAULT_NESTED_DOC_DIR) => {
return dir;
};
/**
*
* @param nodes
* @param nodeData
* @param classes
*/
function insertOrUpdateNode(nodes, nodeData, classes) {
if (!nodeData.id || nodeData.id === '</join></fork>' || nodeData.id === '</choice>') {
return;

View File

@ -11,12 +11,12 @@ import { createRoundedRectPathD } from './shapes/roundedRectPath.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
const rect = async (parent, node) => {
log.info('Creating subgraph rect for ', node.id, node);
const siteConfig = getConfig();
const { themeVariables, handdrawnSeed } = siteConfig;
const { themeVariables, handDrawnSeed } = siteConfig;
const { clusterBkg, clusterBorder } = themeVariables;
const { labelStyles, nodeStyles } = styles2String(node);
@ -33,9 +33,6 @@ const rect = async (parent, node) => {
// Create the label and insert it after the rect
const labelEl = shapeSvg.insert('g').attr('class', 'cluster-label ');
// const text = label
// .node()
// .appendChild(createLabel(node.label, node.labelStyle, undefined, true));
const text = await createText(labelEl, node.label, {
style: node.labelStyle,
useHtmlLabels,
@ -53,10 +50,7 @@ const rect = async (parent, node) => {
dv.attr('height', bbox.height);
}
const padding = 0 * node.padding;
const width =
(node.width <= bbox.width + node.padding ? bbox.width + node.padding : node.width) + padding;
const width = node.width <= bbox.width + node.padding ? bbox.width + node.padding : node.width;
if (node.width <= bbox.width + node.padding) {
node.diff = (width - node.width) / 2 - node.padding;
} else {
@ -66,11 +60,10 @@ const rect = async (parent, node) => {
const height = node.height;
const x = node.x - width / 2;
const y = node.y - height / 2;
// console.log('UIO diff 2', node.id, node.diff, 'totalWidth: ', width);
log.trace('Data ', node, JSON.stringify(node));
let rect;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore TODO: Fix rough typings
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {
@ -79,10 +72,9 @@ const rect = async (parent, node) => {
// fill: 'red',
stroke: clusterBorder,
fillWeight: 3,
seed: handdrawnSeed,
seed: handDrawnSeed,
});
const roughNode = rc.path(createRoundedRectPathD(x, y, width, height, 0), options);
// console.log('Rough node insert CXC', roughNode);
rect = shapeSvg.insert(() => {
log.debug('Rough node insert CXC', roughNode);
return roughNode;
@ -170,7 +162,7 @@ const noteGroup = (parent, node) => {
const roundedWithTitle = async (parent, node) => {
const siteConfig = getConfig();
const { themeVariables, handdrawnSeed } = siteConfig;
const { themeVariables, handDrawnSeed } = siteConfig;
const { altBackground, compositeBackground, compositeTitleBackground, nodeBorder } =
themeVariables;
@ -226,7 +218,7 @@ const roundedWithTitle = async (parent, node) => {
// add the rect
let rect;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
const isAlt = node.cssClasses.includes('statediagram-cluster-alt');
const rc = rough.svg(shapeSvg);
const roughOuterNode =
@ -236,16 +228,16 @@ const roundedWithTitle = async (parent, node) => {
fill: compositeTitleBackground,
fillStyle: 'solid',
stroke: nodeBorder,
seed: handdrawnSeed,
seed: handDrawnSeed,
})
: rc.rectangle(x, y, width, height, { seed: handdrawnSeed });
: rc.rectangle(x, y, width, height, { seed: handDrawnSeed });
rect = shapeSvg.insert(() => roughOuterNode, ':first-child');
const roughInnerNode = rc.rectangle(x, innerY, width, innerHeight, {
fill: isAlt ? altBackground : compositeBackground,
fillStyle: isAlt ? 'hachure' : 'solid',
stroke: nodeBorder,
seed: handdrawnSeed,
seed: handDrawnSeed,
});
rect = shapeSvg.insert(() => roughOuterNode, ':first-child');
@ -291,7 +283,7 @@ const roundedWithTitle = async (parent, node) => {
const divider = (parent, node) => {
const siteConfig = getConfig();
const { themeVariables, handdrawnSeed } = siteConfig;
const { themeVariables, handDrawnSeed } = siteConfig;
const { nodeBorder } = themeVariables;
// Add outer g element
@ -318,14 +310,14 @@ const divider = (parent, node) => {
// add the rect
let rect;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
const rc = rough.svg(shapeSvg);
const roughOuterNode = rc.rectangle(x, y, width, height, {
fill: 'lightgrey',
roughness: 0.5,
strokeLineDash: [5],
stroke: nodeBorder,
seed: handdrawnSeed,
seed: handDrawnSeed,
});
rect = shapeSvg.insert(() => roughOuterNode, ':first-child');

View File

@ -31,7 +31,7 @@ async function addHtmlLabel(node) {
'<span class="' +
labelClass +
'" ' +
(node.labelStyle ? 'style="' + node.labelStyle + '"' : '') +
(node.labelStyle ? 'style="' + node.labelStyle + '"' : '') + // codeql [js/html-constructed-from-input] : false positive
'>' +
label +
'</span>'

View File

@ -423,7 +423,7 @@ const fixCorners = function (lineData) {
};
export const insertEdge = function (elem, edge, clusterDb, diagramType, startNode, endNode, id) {
const { handdrawnSeed } = getConfig();
const { handDrawnSeed } = getConfig();
let points = edge.points;
let pointsHasChanged = false;
const tail = startNode;
@ -510,13 +510,13 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
let svgPath;
let linePath = lineFunction(lineData);
const edgeStyles = Array.isArray(edge.style) ? edge.style : [edge.style];
if (edge.look === 'handdrawn') {
if (edge.look === 'handDrawn') {
const rc = rough.svg(elem);
Object.assign([], lineData);
const svgPathNode = rc.path(linePath, {
roughness: 0.3,
seed: handdrawnSeed,
seed: handDrawnSeed,
});
strokeClasses += ' transition';

View File

@ -38,6 +38,10 @@ import { titledCylinder } from './shapes/tiltedCylinder.js';
import { trapezoidalPentagon } from './shapes/trapezoidalPentagon.js';
import { flippedTriangle } from './shapes/flippedTriangle.js';
import { hourglass } from './shapes/hourglass.js';
import { taggedRect } from './shapes/taggedRect.js';
import { multiRect } from './shapes/multiRect.js';
import { linedCylinder } from './shapes/linedCylinder.js';
import { waveEdgedRectangle } from './shapes/waveEdgedRectangle.js';
const shapes = {
state,
@ -79,6 +83,10 @@ const shapes = {
trapezoidalPentagon,
flippedTriangle,
hourglass,
taggedRect,
multiRect,
linedCylinder,
waveEdgedRectangle,
};
const nodeElems = new Map();

View File

@ -1,17 +1,16 @@
import { log } from '$root/logger.js';
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
import { updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
export const anchor = async (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
const { labelStyles, nodeStyles } = styles2String(node);
export const anchor = (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
const { labelStyles } = styles2String(node);
node.labelStyle = labelStyles;
// const { shapeSvg, bbox, halfPadding } = await labelHelper(parent, node, getNodeClasses(node));
const classes = getNodeClasses(node);
let cssClasses = classes;
if (!classes) {
@ -23,32 +22,19 @@ export const anchor = async (parent: SVGAElement, node: Node): Promise<SVGAEleme
.attr('id', node.domId || node.id);
const radius = 1;
let circleElem;
const { cssStyles } = node;
// if (node.look === 'handdrawn') {
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, { fill: 'black', stroke: 'none', fillStyle: 'solid' });
if (node.look !== 'handdrawn') {
if (node.look !== 'handDrawn') {
options.roughness = 0;
}
const roughNode = rc.circle(0, 0, radius * 2, options);
console.log('IPI roughNode:', options);
circleElem = shapeSvg.insert(() => roughNode, ':first-child');
const circleElem = shapeSvg.insert(() => roughNode, ':first-child');
circleElem.attr('class', 'anchor').attr('style', cssStyles);
// } else {
// circleElem = shapeSvg
// .insert('circle', ':first-child')
// .attr('class', 'basic label-container')
// .attr('style', nodeStyles)
// .attr('r', radius)
// .attr('cx', 0)
// .attr('cy', 0);
// }
updateNodeBounds(node, circleElem);

View File

@ -4,7 +4,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
function createBowTieRectPathD(x: number, y: number, totalWidth: number, totalHeight: number) {
@ -21,7 +21,7 @@ export const bowTieRect = async (parent: SVGAElement, node: Node) => {
let shape: d3.Selection<SVGPathElement | SVGGElement, unknown, null, undefined>;
const { cssStyles } = node;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const pathData = createBowTieRectPathD(0, 0, w, h);

View File

@ -4,7 +4,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
@ -21,17 +21,13 @@ export async function card(parent: SVGAElement, node: Node): Promise<SVGAElement
node.labelStyle = labelStyles;
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
const f = 4;
const h = bbox.height + node.padding;
// const m = h / f;
const m = 10;
const padding = 12;
const w = bbox.width + node.padding + padding;
const left = 0;
const right = w;
const top = -h;
const bottom = 0;
// const w = bbox.width + 2 * m + node.padding;
const points = [
{ x: left + padding, y: top },
{ x: right, y: top },
@ -44,7 +40,7 @@ export async function card(parent: SVGAElement, node: Node): Promise<SVGAElement
let polygon: d3.Selection<SVGPolygonElement | SVGGElement, unknown, null, undefined>;
const { cssStyles } = node;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});

View File

@ -3,7 +3,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import type { SVG } from '$root/diagram-api/types.js';
// @ts-ignore TODO: Fix rough typings
import rough from 'roughjs';
import { solidStateFill, styles2String } from './handdrawnStyles.js';
import { solidStateFill, styles2String } from './handDrawnShapeStyles.js';
import { getConfig } from '$root/diagram-api/diagramAPI.js';
export const choice = (parent: SVG, node: Node) => {
@ -25,7 +25,7 @@ export const choice = (parent: SVG, node: Node) => {
];
let choice;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore TODO: Fix rough typings
const rc = rough.svg(shapeSvg);
const pointArr = points.map(function (d) {

View File

@ -5,7 +5,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
export const circle = async (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
@ -17,7 +17,7 @@ export const circle = async (parent: SVGAElement, node: Node): Promise<SVGAEleme
let circleElem;
const { cssStyles } = node;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});

View File

@ -4,7 +4,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
import intersect from '../intersect/index.js';
@ -33,7 +33,7 @@ export const crossedCircle = async (parent: SVGAElement, node: Node) => {
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
if (node.look !== 'handdrawn') {
if (node.look !== 'handDrawn') {
options.roughness = 0;
options.fillStyle = 'solid';
}

View File

@ -4,7 +4,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
function createCurvedTrapezoidPathD(
@ -43,7 +43,7 @@ export const curvedTrapezoid = async (parent: SVGAElement, node: Node) => {
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
if (node.look !== 'handdrawn') {
if (node.look !== 'handDrawn') {
options.roughness = 0;
options.fillStyle = 'solid';
}

View File

@ -4,7 +4,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
export const createCylinderPathD = (
@ -63,7 +63,7 @@ export const cylinder = async (parent: SVGAElement, node: Node) => {
let cylinder: d3.Selection<SVGPathElement | SVGGElement, unknown, null, undefined>;
const { cssStyles } = node;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const outerPathData = createOuterCylinderPathD(0, 0, w, h, rx, ry);

View File

@ -4,7 +4,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
export function createDividedRectPathD(
@ -48,7 +48,7 @@ export const dividedRect = async (parent: SVGAElement, node: Node) => {
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
if (node.look !== 'handdrawn') {
if (node.look !== 'handDrawn') {
options.roughness = 0;
options.fillStyle = 'solid';
}

View File

@ -4,7 +4,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
export const createCylinderPathD = (
@ -63,7 +63,7 @@ export const cylinder = async (parent: SVGAElement, node: Node) => {
let cylinder: d3.Selection<SVGPathElement | SVGGElement, unknown, null, undefined>;
const { cssStyles } = node;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const outerPathData = createOuterCylinderPathD(0, 0, w, h, rx, ry);

View File

@ -5,7 +5,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
export const doublecircle = async (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
@ -19,7 +19,7 @@ export const doublecircle = async (parent: SVGAElement, node: Node): Promise<SVG
let circleGroup;
const { cssStyles } = node;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const outerOptions = userNodeOverrides(node, { roughness: 0.2, strokeWidth: 2.5 });

View File

@ -5,7 +5,7 @@ import { createRoundedRectPathD } from './roundedRectPath.js';
import {
userNodeOverrides,
styles2String,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
export const drawRect = async (parent: SVGAElement, node: Node, options: RectOptions) => {
@ -31,7 +31,7 @@ export const drawRect = async (parent: SVGAElement, node: Node, options: RectOpt
ry = options.ry;
}
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore TODO: Fix rough typings
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});

View File

@ -5,7 +5,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
import { createPathFromPoints } from './util.js';
@ -27,7 +27,7 @@ export const flippedTriangle = async (parent: SVGAElement, node: Node): Promise<
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
if (node.look !== 'handdrawn') {
if (node.look !== 'handDrawn') {
options.roughness = 0;
options.fillStyle = 'solid';
}

View File

@ -3,7 +3,7 @@ import intersect from '../intersect/index.js';
import type { Node } from '$root/rendering-util/types.d.ts';
import type { SVG } from '$root/diagram-api/types.js';
import rough from 'roughjs';
import { solidStateFill } from './handdrawnStyles.js';
import { solidStateFill } from './handDrawnShapeStyles.js';
import { getConfig } from '$root/diagram-api/diagramAPI.js';
export const forkJoin = (parent: SVG, node: Node, dir: string) => {
@ -25,7 +25,7 @@ export const forkJoin = (parent: SVG, node: Node, dir: string) => {
const y = (-1 * height) / 2;
let shape;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore TODO: Fix rough typings
const rc = rough.svg(shapeSvg);
const roughNode = rc.rectangle(x, y, width, height, solidStateFill(lineColor));

View File

@ -5,7 +5,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
function createHalfRoundedRectShapePathD(
@ -45,7 +45,7 @@ export const halfRoundedRectangle = async (parent: SVGAElement, node: Node) => {
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
if (node.look !== 'handdrawn') {
if (node.look !== 'handDrawn') {
options.roughness = 0;
options.fillStyle = 'solid';
}

View File

@ -3,7 +3,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
// Striped fill like start or fork nodes in state diagrams
export const solidStateFill = (color: string) => {
const { handdrawnSeed } = getConfig();
const { handDrawnSeed } = getConfig();
return {
fill: color,
hachureAngle: 120, // angle of hachure,
@ -11,7 +11,7 @@ export const solidStateFill = (color: string) => {
fillWeight: 2,
roughness: 0.7,
stroke: color,
seed: handdrawnSeed,
seed: handDrawnSeed,
};
};
@ -72,7 +72,7 @@ export const styles2String = (node: Node) => {
// Striped fill like start or fork nodes in state diagrams
// TODO remove any
export const userNodeOverrides = (node: Node, options: any) => {
const { themeVariables, handdrawnSeed } = getConfig();
const { themeVariables, handDrawnSeed } = getConfig();
const { nodeBorder, mainBkg } = themeVariables;
const { stylesMap } = compileStyles(node);
@ -84,7 +84,7 @@ export const userNodeOverrides = (node: Node, options: any) => {
fillStyle: 'hachure', // solid fill
fillWeight: 4,
stroke: stylesMap.get('stroke') || nodeBorder,
seed: handdrawnSeed,
seed: handDrawnSeed,
strokeWidth: 1.3,
},
options

View File

@ -4,7 +4,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
@ -48,7 +48,7 @@ export const hexagon = async (parent: SVGAElement, node: Node): Promise<SVGAElem
let polygon: d3.Selection<SVGPolygonElement | SVGGElement, unknown, null, undefined>;
const { cssStyles } = node;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});

View File

@ -5,7 +5,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
export const hourglass = async (parent: SVGAElement, node: Node) => {
@ -23,7 +23,7 @@ export const hourglass = async (parent: SVGAElement, node: Node) => {
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
if (node.look !== 'handdrawn') {
if (node.look !== 'handDrawn') {
options.roughness = 0;
options.fillStyle = 'solid';
}

View File

@ -4,7 +4,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
@ -40,7 +40,7 @@ export const inv_trapezoid = async (parent: SVGAElement, node: Node): Promise<SV
let polygon: d3.Selection<SVGPolygonElement | SVGGElement, unknown, null, undefined>;
const { cssStyles } = node;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});

View File

@ -4,7 +4,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
@ -40,7 +40,7 @@ export const lean_left = async (parent: SVGAElement, node: Node): Promise<SVGAEl
let polygon: d3.Selection<SVGPolygonElement | SVGGElement, unknown, null, undefined>;
const { cssStyles } = node;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});

View File

@ -4,7 +4,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
@ -40,7 +40,7 @@ export const lean_right = async (parent: SVGAElement, node: Node): Promise<SVGAE
let polygon: d3.Selection<SVGPolygonElement | SVGGElement, unknown, null, undefined>;
const { cssStyles } = node;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});

View File

@ -0,0 +1,96 @@
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '$root/rendering-util/types.d.ts';
import rough from 'roughjs';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
export const createCylinderPathWithInnerArcD = (
x: number,
y: number,
width: number,
height: number,
rx: number,
ry: number,
outerOffset: number
): string => {
return [
`M${x},${y + ry}`,
`a${rx},${ry} 0,0,0 ${width},0`,
`a${rx},${ry} 0,0,0 ${-width},0`,
`l0,${height}`,
`a${rx},${ry} 0,0,0 ${width},0`,
`l0,${-height}`,
`M${x},${y + ry + outerOffset}`, // Move to the start of the offset top arc
`a${rx},${ry} 0,0,0 ${width},0`, // Draw the duplicated top ellipse
].join(' ');
};
export const linedCylinder = async (parent: SVGAElement, node: Node) => {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node));
const w = bbox.width + node.padding;
const rx = w / 2;
const ry = rx / (2.5 + w / 50);
const h = bbox.height + ry + node.padding;
const outerOffset = h * 0.1; // 10% of height
let cylinder: d3.Selection<SVGPathElement | SVGGElement, unknown, null, undefined>;
const { cssStyles } = node;
if (node.look === 'handDrawn') {
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
const pathData = createCylinderPathWithInnerArcD(0, ry, w, h, rx, ry, outerOffset);
const innerLine = rc.path(pathData, options);
cylinder = shapeSvg.insert(() => innerLine, ':first-child');
cylinder.attr('class', 'basic label-container');
if (cssStyles) {
cylinder.attr('style', cssStyles);
}
} else {
const pathData = createCylinderPathWithInnerArcD(0, 0, w, h, rx, ry, outerOffset);
cylinder = shapeSvg
.insert('path', ':first-child')
.attr('d', pathData)
.attr('class', 'basic label-container')
.attr('style', cssStyles)
.attr('style', nodeStyles);
}
cylinder.attr('label-offset-y', ry);
cylinder.attr('transform', `translate(${-w / 2}, ${-(h / 2 + ry)})`);
updateNodeBounds(node, cylinder);
label.attr('transform', `translate(${-bbox.width / 2}, ${h / 2 - bbox.height + outerOffset})`);
node.intersect = function (point) {
const pos = intersect.rect(node, point);
const x = pos.x - (node.x ?? 0);
if (
rx != 0 &&
(Math.abs(x) < (node.width ?? 0) / 2 ||
(Math.abs(x) == (node.width ?? 0) / 2 &&
Math.abs(pos.y - (node.y ?? 0)) > (node.height ?? 0) / 2 - ry))
) {
let y = ry * ry * (1 - (x * x) / (rx * rx));
if (y != 0) {
y = Math.sqrt(y);
}
y = ry - y;
if (point.y - (node.y ?? 0) > 0) {
y = -y;
}
pos.y += y;
}
return pos;
};
return shapeSvg;
};

View File

@ -0,0 +1,87 @@
import { labelHelper, getNodeClasses, updateNodeBounds, createPathFromPoints } from './util.js';
import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
import intersect from '../intersect/index.js';
export const multiRect = async (parent: SVGAElement, node: Node) => {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node));
const h = bbox.height + node.padding;
const w = bbox.width + node.padding;
const x = -w / 2;
const y = -h / 2;
const rectOffset = 5;
const { cssStyles } = node;
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
const rectPoints = [
{ x, y },
{ x: x + w, y },
{ x: x + w, y: y + h },
{ x, y: y + h },
];
const secondRectPoints = [
{ x: x + rectOffset, y: y - rectOffset },
{ x: x + w + rectOffset, y: y - rectOffset },
{ x: x + w + rectOffset, y: y + h - rectOffset },
{ x: x + rectOffset, y: y + h - rectOffset },
];
const thirdRectPoints = [
{ x: x + 2 * rectOffset, y: y - 2 * rectOffset },
{ x: x + w + 2 * rectOffset, y: y - 2 * rectOffset },
{ x: x + w + 2 * rectOffset, y: y + h - 2 * rectOffset },
{ x: x + 2 * rectOffset, y: y + h - 2 * rectOffset },
];
if (node.look !== 'handdrawn') {
options.roughness = 0;
options.fillStyle = 'solid';
}
const rectPath = createPathFromPoints(rectPoints);
const rectNode = rc.path(rectPath, options);
const secondRectPath = createPathFromPoints(secondRectPoints);
const secondRectNode = rc.path(secondRectPath, options);
const thirdRectPath = createPathFromPoints(thirdRectPoints);
const thirdRectNode = rc.path(thirdRectPath, options);
const taggedRect = shapeSvg.insert('g', ':first-child');
taggedRect.insert(() => thirdRectNode, ':first-child');
taggedRect.insert(() => secondRectNode);
taggedRect.insert(() => rectNode);
taggedRect.attr('class', 'basic label-container');
if (cssStyles) {
taggedRect.attr('style', cssStyles);
}
if (nodeStyles) {
taggedRect.attr('style', nodeStyles);
}
taggedRect.attr('transform', `translate(-${rectOffset},${rectOffset})`);
label.attr(
'transform',
`translate(${-(bbox.width / 2) - rectOffset}, ${h / 2 - bbox.height - 4 * rectOffset})`
);
updateNodeBounds(node, taggedRect);
node.intersect = function (point) {
const pos = intersect.rect(node, point);
return pos;
};
return shapeSvg;
};

View File

@ -6,7 +6,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import rough from 'roughjs';
export const note = async (parent: SVGAElement, node: Node) => {
const { themeVariables, handdrawnSeed } = getConfig();
const { themeVariables, handDrawnSeed } = getConfig();
const { noteBorderColor, noteBkgColor } = themeVariables;
const useHtmlLabels = node.useHtmlLabels;
@ -23,7 +23,7 @@ export const note = async (parent: SVGAElement, node: Node) => {
const x = -totalWidth / 2;
const y = -totalHeight / 2;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// add the rect
// @ts-ignore TODO: Fix rough typings
const rc = rough.svg(shapeSvg);
@ -31,7 +31,7 @@ export const note = async (parent: SVGAElement, node: Node) => {
roughness: 0.7,
fill: noteBkgColor,
fillWeight: 3,
seed: handdrawnSeed,
seed: handDrawnSeed,
// fillStyle: 'solid', // solid fill'
stroke: noteBorderColor,
});

View File

@ -5,7 +5,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
@ -38,7 +38,7 @@ export const question = async (parent: SVGAElement, node: Node): Promise<SVGAEle
let polygon: d3.Selection<SVGPolygonElement | SVGGElement, unknown, null, undefined>;
const { cssStyles } = node;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});

View File

@ -4,7 +4,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
@ -40,7 +40,7 @@ export const rect_left_inv_arrow = async (
let polygon;
const { cssStyles } = node;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});

View File

@ -7,7 +7,7 @@ import intersect from '../intersect/index.js';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
import { getConfig } from '$root/diagram-api/diagramAPI.js';
import { createRoundedRectPathD } from './roundedRectPath.js';
@ -104,7 +104,7 @@ export const rectWithTitle = async (parent: SVGElement, node: Node) => {
const y = -bbox.height / 2 - halfPadding;
let rect;
let innerLine;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore No typings for rough
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -134,6 +134,7 @@ export const rectWithTitle = async (parent: SVGElement, node: Node) => {
innerLine = g.insert('line');
rect
.attr('class', 'outer title-state')
.attr('style', nodeStyles)
.attr('x', -bbox.width / 2 - halfPadding)
.attr('y', -bbox.height / 2 - halfPadding)
.attr('width', bbox.width + (node.padding || 0))

View File

@ -4,10 +4,8 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
import { createPathFromPoints } from './util.js';
export const shadedProcess = async (parent: SVGAElement, node: Node) => {
const { labelStyles, nodeStyles } = styles2String(node);
@ -18,26 +16,13 @@ export const shadedProcess = async (parent: SVGAElement, node: Node) => {
const h = bbox.height + node.padding;
const x = -bbox.width / 2 - halfPadding;
const y = -bbox.height / 2 - halfPadding;
let rect;
const { cssStyles } = node;
const points = [
{ x: 0, y: 0 },
{ x: w, y: 0 },
{ x: w, y: -h },
{ x: 0, y: -h },
{ x: 0, y: 0 },
{ x: -8, y: 0 },
{ x: w + 8, y: 0 },
{ x: w + 8, y: -h },
{ x: -8, y: -h },
{ x: -8, y: 0 },
];
const { cssStyles } = node;
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
if (node.look !== 'handdrawn') {
if (node.look !== 'handDrawn') {
options.roughness = 0;
options.fillStyle = 'solid';
}
@ -46,7 +31,7 @@ export const shadedProcess = async (parent: SVGAElement, node: Node) => {
const l1 = rc.line(x, y, x, y + h, options);
shapeSvg.insert(() => l1, ':first-child');
rect = shapeSvg.insert(() => roughNode, ':first-child');
const rect = shapeSvg.insert(() => roughNode, ':first-child');
rect.attr('class', 'basic label-container').attr('style', cssStyles);

View File

@ -4,7 +4,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
function createSlopedRectPathD(x: number, y: number, totalWidth: number, totalHeight: number) {
@ -36,7 +36,7 @@ export const slopedRect = async (parent: SVGAElement, node: Node) => {
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
if (node.look !== 'handdrawn') {
if (node.look !== 'handDrawn') {
options.roughness = 0;
options.fillStyle = 'solid';
}

View File

@ -4,7 +4,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
import { createRoundedRectPathD } from './roundedRectPath.js';
@ -63,7 +63,7 @@ export const stadium = async (parent: SVGAElement, node: Node) => {
let rect;
const { cssStyles } = node;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});

View File

@ -3,7 +3,7 @@ import intersect from '../intersect/index.js';
import type { Node } from '$root/rendering-util/types.d.ts';
import type { SVG } from '$root/diagram-api/types.js';
import rough from 'roughjs';
import { solidStateFill } from './handdrawnStyles.js';
import { solidStateFill } from './handDrawnShapeStyles.js';
import { getConfig } from '$root/diagram-api/diagramAPI.js';
export const stateEnd = (parent: SVG, node: Node) => {
@ -16,7 +16,7 @@ export const stateEnd = (parent: SVG, node: Node) => {
let circle;
let innerCircle;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore TODO: Fix rough typings
const rc = rough.svg(shapeSvg);
const roughNode = rc.circle(0, 0, 14, { ...solidStateFill(lineColor), roughness: 0.5 });

View File

@ -3,7 +3,7 @@ import intersect from '../intersect/index.js';
import type { Node } from '$root/rendering-util/types.d.ts';
import type { SVG } from '$root/diagram-api/types.js';
import rough from 'roughjs';
import { solidStateFill } from './handdrawnStyles.js';
import { solidStateFill } from './handDrawnShapeStyles.js';
import { getConfig } from '$root/diagram-api/diagramAPI.js';
export const stateStart = (parent: SVG, node: Node) => {
@ -16,7 +16,7 @@ export const stateStart = (parent: SVG, node: Node) => {
.attr('id', node.domId || node.id);
let circle;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore TODO: Fix rough typings
const rc = rough.svg(shapeSvg);
const roughNode = rc.circle(0, 0, 14, solidStateFill(lineColor));

View File

@ -4,7 +4,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
@ -43,8 +43,7 @@ export const subroutine = async (parent: SVGAElement, node: Node) => {
const h = bbox.height + node.padding;
const x = -bbox.width / 2 - halfPadding;
const y = -bbox.height / 2 - halfPadding;
let rect;
const { cssStyles } = node;
const points = [
{ x: 0, y: 0 },
{ x: w, y: 0 },
@ -58,7 +57,7 @@ export const subroutine = async (parent: SVGAElement, node: Node) => {
{ x: -8, y: 0 },
];
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
@ -69,9 +68,10 @@ export const subroutine = async (parent: SVGAElement, node: Node) => {
shapeSvg.insert(() => l1, ':first-child');
shapeSvg.insert(() => l2, ':first-child');
rect = shapeSvg.insert(() => roughNode, ':first-child');
const rect = shapeSvg.insert(() => roughNode, ':first-child');
const { cssStyles } = node;
rect.attr('class', 'basic label-container').attr('style', cssStyles);
updateNodeBounds(node, rect);
} else {
const el = insertPolygonShape(shapeSvg, w, h, points);
if (nodeStyles) {

View File

@ -0,0 +1,73 @@
import { labelHelper, getNodeClasses, updateNodeBounds, createPathFromPoints } from './util.js';
import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
import intersect from '../intersect/index.js';
export const taggedRect = async (parent: SVGAElement, node: Node) => {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
const h = bbox.height + node.padding;
const w = bbox.width + node.padding;
const x = -w / 2;
const y = -h / 2;
const tagWidth = 0.2 * w;
const tagHeight = 0.2 * h;
const { cssStyles } = node;
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
const rectPoints = [
{ x, y },
{ x: x + w, y },
{ x: x + w, y: y + h },
{ x, y: y + h },
];
const tagPoints = [
{ x: x + w - tagWidth, y: y + h },
{ x: x + w, y: y + h },
{ x: x + w, y: y + h - tagHeight },
];
if (node.look !== 'handDrawn') {
options.roughness = 0;
options.fillStyle = 'solid';
}
const rectPath = createPathFromPoints(rectPoints);
const rectNode = rc.path(rectPath, options);
const tagPath = createPathFromPoints(tagPoints);
const tagNode = rc.path(tagPath, options);
const taggedRect = shapeSvg.insert('g', ':first-child');
taggedRect.insert(() => rectNode, ':first-child');
taggedRect.insert(() => tagNode);
taggedRect.attr('class', 'basic label-container');
if (cssStyles) {
taggedRect.attr('style', cssStyles);
}
if (nodeStyles) {
taggedRect.attr('style', nodeStyles);
}
updateNodeBounds(node, taggedRect);
node.intersect = function (point) {
const pos = intersect.rect(node, point);
return pos;
};
return shapeSvg;
};

View File

@ -1,12 +1,12 @@
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '$root/rendering-util/types.d.ts';
import { styles2String } from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
import { styles2String } from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
export async function text(parent: SVGAElement, node: Node): Promise<SVGAElement> {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
// console.log('IPI labelStyles:', labelStyles);
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
const totalWidth = Math.max(bbox.width + node.padding, node?.width || 0);
@ -14,12 +14,7 @@ export async function text(parent: SVGAElement, node: Node): Promise<SVGAElement
const x = -totalWidth / 2;
const y = -totalHeight / 2;
// log.info('IPI node = ', node);
let rect;
const { cssStyles } = node;
rect = shapeSvg.insert('rect', ':first-child');
const rect = shapeSvg.insert('rect', ':first-child');
rect
.attr('class', 'text')

View File

@ -3,7 +3,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
import intersect from '../intersect/index.js';
@ -30,7 +30,7 @@ export const titledCylinder = async (parent: SVGAElement, node: Node) => {
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
if (node.look !== 'handdrawn') {
if (node.look !== 'handDrawn') {
options.roughness = 0;
options.fillStyle = 'solid';
}

View File

@ -4,7 +4,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
import { insertPolygonShape } from './insertPolygonShape.js';
@ -40,7 +40,7 @@ export const trapezoid = async (parent: SVGAElement, node: Node): Promise<SVGAEl
let polygon: d3.Selection<SVGPolygonElement | SVGGElement, unknown, null, undefined>;
const { cssStyles } = node;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});

View File

@ -4,7 +4,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
function createTrapezoidalPentagonPathD(width = 100, height = 80) {
@ -35,7 +35,7 @@ export const trapezoidalPentagon = async (parent: SVGAElement, node: Node) => {
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
if (node.look !== 'handdrawn') {
if (node.look !== 'handDrawn') {
options.roughness = 0;
options.fillStyle = 'solid';
}

View File

@ -5,7 +5,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
import { createPathFromPoints } from './util.js';
@ -27,7 +27,7 @@ export const triangle = async (parent: SVGAElement, node: Node): Promise<SVGAEle
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
if (node.look !== 'handdrawn') {
if (node.look !== 'handDrawn') {
options.roughness = 0;
options.fillStyle = 'solid';
}

View File

@ -133,7 +133,7 @@ export function insertPolygonShape(parent, w, h, points) {
}
export const getNodeClasses = (node, extra) =>
(node.look === 'handdrawn' ? 'rough-node' : 'node') + ' ' + node.cssClasses + ' ' + (extra || '');
(node.look === 'handDrawn' ? 'rough-node' : 'node') + ' ' + node.cssClasses + ' ' + (extra || '');
export function createPathFromPoints(points) {
const pointStrings = points.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x},${p.y}`);

View File

@ -0,0 +1,80 @@
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
import intersect from '../intersect/index.js';
import type { Node } from '$root/rendering-util/types.d.ts';
import rough from 'roughjs';
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
export function createWaveEdgedRectanglePathD(width: number, height: number) {
// Calculate control points
const rightX = width;
const midX = width / 2;
const controlY1 = height * 0.8;
const controlY2 = height * 1.15;
const endY = height * 0.94;
// Construct the path
const path = `M0 0
H${rightX}
V${controlY1}
C${midX} ${controlY1}, ${midX} ${controlY2}, 0 ${endY}
Z`;
return path;
}
export const waveEdgedRectangle = async (parent: SVGAElement, node: Node) => {
const { labelStyles, nodeStyles } = styles2String(node);
node.labelStyle = labelStyles;
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
const w = bbox.width + node.padding;
const h = bbox.height + node.padding + 20;
const { cssStyles } = node;
const rightX = w;
const midX = w / 2;
const controlY1 = h * 0.8;
const controlY2 = h * 1.15;
const endY = h * 0.94;
const points = [
{ x: 0, y: 0 },
{ x: rightX, y: 0 },
{ x: rightX, y: controlY1 },
{ x: midX, y: controlY1 },
{ x: midX, y: controlY2 * 0.8 },
{ x: 0, y: endY },
];
const pathData = createWaveEdgedRectanglePathD(w, h);
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const options = userNodeOverrides(node, {});
if (node.look !== 'handDrawn') {
options.roughness = 0;
options.fillStyle = 'solid';
}
const shapeNode = rc.path(pathData, options);
const shape = shapeSvg.insert(() => shapeNode, ':first-child');
shape.attr('class', 'basic label-container');
if (cssStyles) {
shape.attr('style', cssStyles);
}
if (nodeStyles) {
shape.attr('style', nodeStyles);
}
shape.attr('transform', `translate(${-w / 2}, ${-h / 2})`);
updateNodeBounds(node, shape);
node.intersect = function (point) {
const pos = intersect.polygon(node, points, point);
return pos;
};
return shapeSvg;
};

View File

@ -4,7 +4,7 @@ import type { Node } from '$root/rendering-util/types.d.ts';
import {
styles2String,
userNodeOverrides,
} from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import rough from 'roughjs';
function createWaveRectanglePathD(x: number, y: number, width: number, height: number) {
@ -32,7 +32,7 @@ export const waveRectangle = async (parent: SVGAElement, node: Node) => {
let shape: d3.Selection<SVGPathElement | SVGGElement, unknown, null, undefined>;
const { cssStyles } = node;
if (node.look === 'handdrawn') {
if (node.look === 'handDrawn') {
// @ts-ignore - rough is not typed
const rc = rough.svg(shapeSvg);
const pathData = createWaveRectanglePathD(0, 0, w, h);

View File

@ -94,7 +94,7 @@ interface Edge {
labelStyle?: string[];
minlen?: number;
pattern?: string;
thickness?: 'normal' | 'thick' | 'invisible';
thickness?: 'normal' | 'thick' | 'invisible' | 'dotted';
look?: string;
}

View File

@ -79,11 +79,11 @@ properties:
type: string
enum:
- classic
- handdrawn
- handDrawn
default: 'classic'
handdrawnSeed:
handDrawnSeed:
description: |
Defines the seed to be used when using handdrawn look. This is important for the automated tests as they will always find differences without the seed. The default value is 0 which gives a random seed.
Defines the seed to be used when using handDrawn look. This is important for the automated tests as they will always find differences without the seed. The default value is 0 which gives a random seed.
type: number
default: 0
layout:

View File

@ -1,6 +1,6 @@
{
"name": "@mermaid-js/parser",
"version": "0.1.0-rc.1",
"version": "0.1.0-rc.2",
"description": "MermaidJS parser",
"author": "Yokozuna59",
"contributors": [

3309
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff