mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-14 06:43:25 +08:00
Merge branch '5237-unified-layout-flowchart' into 5237-unified-layout-common-renderer
This commit is contained in:
commit
51bdda0c34
775
cypress/platform/flowchart-refactor.html
Normal file
775
cypress/platform/flowchart-refactor.html
Normal file
@ -0,0 +1,775 @@
|
|||||||
|
<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" />
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Arial';
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
table-layout: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
border: 1px solid black;
|
||||||
|
padding: 10px;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator {
|
||||||
|
height: 20px;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-header {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapsible {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
color: #444;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 18px;
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
text-align: left;
|
||||||
|
outline: none;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active,
|
||||||
|
.collapsible:hover {
|
||||||
|
background-color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapsible:after {
|
||||||
|
content: '\002B';
|
||||||
|
color: #777;
|
||||||
|
font-weight: bold;
|
||||||
|
float: right;
|
||||||
|
margin-left: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active:after {
|
||||||
|
content: "\2212";
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 0 5px;
|
||||||
|
max-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: max-height 0.2s ease-out;
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content .pre-scrollable {
|
||||||
|
max-height: 200px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th></th> <!-- Placeholder for the top left corner -->
|
||||||
|
<th>Dagre</th>
|
||||||
|
<th>Dagre with rough</th>
|
||||||
|
<th>ELK</th>
|
||||||
|
<th>ELK with rough</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="vertical-header">
|
||||||
|
<button class="collapsible">Stadium shape</button>
|
||||||
|
<div class="content">
|
||||||
|
<div class="pre-scrollable">
|
||||||
|
<pre>
|
||||||
|
flowchart LR
|
||||||
|
id1([This is the text in the box])
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram1" class="mermaid">
|
||||||
|
flowchart LR
|
||||||
|
id1([This is the text in the box])
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram2" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1([This is the text in the box])
|
||||||
|
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram3" class="mermaid">
|
||||||
|
%%{init: {"handdrawn": false, "layout": "elk"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1([This is the text in the box])
|
||||||
|
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram4" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1([This is the text in the box])
|
||||||
|
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<!-- Separator row -->
|
||||||
|
<tr class="separator">
|
||||||
|
<td colspan="5"></td> <!-- This cell spans all columns including the vertical header -->
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th class="vertical-header">
|
||||||
|
<button class="collapsible">Sub-Routine shape</button>
|
||||||
|
<div class="content">
|
||||||
|
<div class="pre-scrollable">
|
||||||
|
<pre>
|
||||||
|
flowchart LR
|
||||||
|
id1[[This is the text in the box]]
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram5" class="mermaid">
|
||||||
|
flowchart LR
|
||||||
|
id1[[This is the text in the box]]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram6" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1[[This is the text in the box]]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram7" class="mermaid">
|
||||||
|
%%{init: {"handdrawn": false, "layout": "elk"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1[[This is the text in the box]]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram8" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1[[This is the text in the box]]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<!-- Separator row -->
|
||||||
|
<tr class="separator">
|
||||||
|
<td colspan="5"></td> <!-- This cell spans all columns including the vertical header -->
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th class="vertical-header">
|
||||||
|
<button class="collapsible">Cylindrical shape</button>
|
||||||
|
<div class="content">
|
||||||
|
<div class="pre-scrollable">
|
||||||
|
<pre>
|
||||||
|
flowchart LR
|
||||||
|
id1[(Database)]
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram9" class="mermaid">
|
||||||
|
flowchart LR
|
||||||
|
id1[(Database)]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram10" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1[(Database)]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram11" class="mermaid">
|
||||||
|
%%{init: {"handdrawn": false, "layout": "elk"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1[(Database)]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram12" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1[(Database)]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<!-- Separator row -->
|
||||||
|
<tr class="separator">
|
||||||
|
<td colspan="5"></td> <!-- This cell spans all columns including the vertical header -->
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th class="vertical-header">
|
||||||
|
<button class="collapsible">Circle shape</button>
|
||||||
|
<div class="content">
|
||||||
|
<div class="pre-scrollable">
|
||||||
|
<pre>
|
||||||
|
flowchart LR
|
||||||
|
id1((This is the text in the circle))
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram13" class="mermaid">
|
||||||
|
flowchart LR
|
||||||
|
id1((This is the text in the circle))
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram14" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1((This is the text in the circle))
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram15" class="mermaid">
|
||||||
|
%%{init: {"handdrawn": false, "layout": "elk"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1((This is the text in the circle))
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram16" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1((This is the text in the circle))
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<!-- Separator row -->
|
||||||
|
<tr class="separator">
|
||||||
|
<td colspan="5"></td> <!-- This cell spans all columns including the vertical header -->
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th class="vertical-header">
|
||||||
|
<button class="collapsible">Double Circle shape</button>
|
||||||
|
<div class="content">
|
||||||
|
<div class="pre-scrollable">
|
||||||
|
<pre>
|
||||||
|
flowchart TD
|
||||||
|
id1(((This is the text in the circle)))
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram17" class="mermaid">
|
||||||
|
flowchart TD
|
||||||
|
id1(((This is the text in the circle)))
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram18" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn"} }%%
|
||||||
|
flowchart TD
|
||||||
|
id1(((This is the text in the circle)))
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram19" class="mermaid">
|
||||||
|
%%{init: {"handdrawn": false, "layout": "elk"} }%%
|
||||||
|
flowchart TD
|
||||||
|
id1(((This is the text in the circle)))
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram20" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
|
||||||
|
flowchart TD
|
||||||
|
id1(((This is the text in the circle)))
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<!-- Separator row -->
|
||||||
|
<tr class="separator">
|
||||||
|
<td colspan="5"></td> <!-- This cell spans all columns including the vertical header -->
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th class="vertical-header">
|
||||||
|
<button class="collapsible">Asymmetric shape</button>
|
||||||
|
<div class="content">
|
||||||
|
<div class="pre-scrollable">
|
||||||
|
<pre>
|
||||||
|
flowchart LR
|
||||||
|
id1>This is the text in the box]
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram21" class="mermaid">
|
||||||
|
flowchart LR
|
||||||
|
id1>This is the text in the box]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram22" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1>This is the text in the box]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram23" class="mermaid">
|
||||||
|
%%{init: {"handdrawn": false, "layout": "elk"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1>This is the text in the box]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram24" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1>This is the text in the box]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<!-- Separator row -->
|
||||||
|
<tr class="separator">
|
||||||
|
<td colspan="5"></td> <!-- This cell spans all columns including the vertical header -->
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th class="vertical-header">
|
||||||
|
<button class="collapsible">Rhombus/Diamond/Question shape</button>
|
||||||
|
<div class="content">
|
||||||
|
<div class="pre-scrollable">
|
||||||
|
<pre>
|
||||||
|
flowchart LR
|
||||||
|
id1{This is the text in the box}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram25" class="mermaid">
|
||||||
|
flowchart LR
|
||||||
|
id1{This is the text in the box}
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram26" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1{This is the text in the box}
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram27" class="mermaid">
|
||||||
|
%%{init: {"handdrawn": false, "layout": "elk"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1{This is the text in the box}
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram28" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1{This is the text in the box}
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<!-- Separator row -->
|
||||||
|
<tr class="separator">
|
||||||
|
<td colspan="5"></td> <!-- This cell spans all columns including the vertical header -->
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th class="vertical-header">
|
||||||
|
<button class="collapsible">Hexagon shape</button>
|
||||||
|
<div class="content">
|
||||||
|
<div class="pre-scrollable">
|
||||||
|
<pre>
|
||||||
|
flowchart LR
|
||||||
|
id1{{This is the text in the box}}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram29" class="mermaid">
|
||||||
|
flowchart LR
|
||||||
|
id1{{This is the text in the box}}
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram30" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1{{This is the text in the box}}
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram31" class="mermaid">
|
||||||
|
%%{init: {"handdrawn": false, "layout": "elk"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1{{This is the text in the box}}
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram32" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1{{This is the text in the box}}
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<!-- Separator row -->
|
||||||
|
<tr class="separator">
|
||||||
|
<td colspan="5"></td> <!-- This cell spans all columns including the vertical header -->
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th class="vertical-header">
|
||||||
|
<button class="collapsible">Parallelogram shape</button>
|
||||||
|
<div class="content">
|
||||||
|
<div class="pre-scrollable">
|
||||||
|
<pre>
|
||||||
|
flowchart TD
|
||||||
|
id1[/This is the text in the box/]
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram33" class="mermaid">
|
||||||
|
flowchart TD
|
||||||
|
id1[/This is the text in the box/]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram34" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn"} }%%
|
||||||
|
flowchart TD
|
||||||
|
id1[/This is the text in the box/]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram35" class="mermaid">
|
||||||
|
%%{init: {"handdrawn": false, "layout": "elk"} }%%
|
||||||
|
flowchart TD
|
||||||
|
id1[/This is the text in the box/]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram36" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
|
||||||
|
flowchart TD
|
||||||
|
id1[/This is the text in the box/]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<!-- Separator row -->
|
||||||
|
<tr class="separator">
|
||||||
|
<td colspan="5"></td> <!-- This cell spans all columns including the vertical header -->
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th class="vertical-header">
|
||||||
|
<button class="collapsible">Parallelogram Alt shape</button>
|
||||||
|
<div class="content">
|
||||||
|
<div class="pre-scrollable">
|
||||||
|
<pre>
|
||||||
|
flowchart TD
|
||||||
|
id1[\This is the text in the box\]
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram37" class="mermaid">
|
||||||
|
flowchart TD
|
||||||
|
id1[\This is the text in the box\]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram38" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn"} }%%
|
||||||
|
flowchart TD
|
||||||
|
id1[\This is the text in the box\]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram39" class="mermaid">
|
||||||
|
%%{init: {"handdrawn": false, "layout": "elk"} }%%
|
||||||
|
flowchart TD
|
||||||
|
id1[\This is the text in the box\]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram40" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
|
||||||
|
flowchart TD
|
||||||
|
id1[\This is the text in the box\]
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<!-- Separator row -->
|
||||||
|
<tr class="separator">
|
||||||
|
<td colspan="5"></td> <!-- This cell spans all columns including the vertical header -->
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th class="vertical-header">
|
||||||
|
<button class="collapsible">Trapezoid shape</button>
|
||||||
|
<div class="content">
|
||||||
|
<div class="pre-scrollable">
|
||||||
|
<pre>
|
||||||
|
flowchart TD
|
||||||
|
A[/Christmas\]
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram41" class="mermaid">
|
||||||
|
flowchart TD
|
||||||
|
A[/Christmas\]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram42" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn"} }%%
|
||||||
|
flowchart TD
|
||||||
|
A[/Christmas\]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram43" class="mermaid">
|
||||||
|
%%{init: {"handdrawn": false, "layout": "elk"} }%%
|
||||||
|
flowchart TD
|
||||||
|
A[/Christmas\]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram44" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
|
||||||
|
flowchart TD
|
||||||
|
A[/Christmas\]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<!-- Separator row -->
|
||||||
|
<tr class="separator">
|
||||||
|
<td colspan="5"></td> <!-- This cell spans all columns including the vertical header -->
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th class="vertical-header">
|
||||||
|
<button class="collapsible">Trapezoid Alt shape</button>
|
||||||
|
<div class="content">
|
||||||
|
<div class="pre-scrollable">
|
||||||
|
<pre>
|
||||||
|
flowchart TD
|
||||||
|
A[\Christmas/]
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram45" class="mermaid">
|
||||||
|
flowchart TD
|
||||||
|
A[\Christmas/]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram46" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn"} }%%
|
||||||
|
flowchart TD
|
||||||
|
A[\Christmas/]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram47" class="mermaid">
|
||||||
|
%%{init: {"handdrawn": false, "layout": "elk"} }%%
|
||||||
|
flowchart TD
|
||||||
|
A[\Christmas/]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram48" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
|
||||||
|
flowchart TD
|
||||||
|
A[\Christmas/]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<!-- Separator row -->
|
||||||
|
<tr class="separator">
|
||||||
|
<td colspan="5"></td> <!-- This cell spans all columns including the vertical header -->
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th class="vertical-header">
|
||||||
|
<button class="collapsible">Rect with rounded corner</button>
|
||||||
|
<div class="content">
|
||||||
|
<div class="pre-scrollable">
|
||||||
|
<pre>
|
||||||
|
flowchart LR
|
||||||
|
id1(This is the text in the box)
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram49" class="mermaid">
|
||||||
|
flowchart LR
|
||||||
|
id1(This is the text in the box)
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram50" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1(This is the text in the box)
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram51" class="mermaid">
|
||||||
|
%%{init: {"handdrawn": false, "layout": "elk"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1(This is the text in the box)
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram52" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1(This is the text in the box)
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<!-- Separator row -->
|
||||||
|
<tr class="separator">
|
||||||
|
<td colspan="5"></td> <!-- This cell spans all columns including the vertical header -->
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th class="vertical-header">
|
||||||
|
<button class="collapsible">Rect with sharp corner</button>
|
||||||
|
<div class="content">
|
||||||
|
<div class="pre-scrollable">
|
||||||
|
<pre>
|
||||||
|
flowchart LR
|
||||||
|
id1[This is the text in the box]
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram53" class="mermaid">
|
||||||
|
flowchart LR
|
||||||
|
id1[This is the text in the box]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram54" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1[This is the text in the box]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram55" class="mermaid">
|
||||||
|
%%{init: {"handdrawn": false, "layout": "elk"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1[This is the text in the box]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram56" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn", "layout": "elk"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1[This is the text in the box]
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<!-- Separator row -->
|
||||||
|
<tr class="separator">
|
||||||
|
<td colspan="5"></td> <!-- This cell spans all columns including the vertical header -->
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
<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) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
mermaid.initialize({
|
||||||
|
handdrawn: false,
|
||||||
|
mergeEdges: true,
|
||||||
|
layout: 'dagre',
|
||||||
|
flowchart: { titleTopMargin: 10 },
|
||||||
|
// fontFamily: 'Caveat',
|
||||||
|
fontFamily: 'Kalam',
|
||||||
|
sequence: {
|
||||||
|
actorFontFamily: 'courier',
|
||||||
|
noteFontFamily: 'courier',
|
||||||
|
messageFontFamily: 'courier',
|
||||||
|
},
|
||||||
|
fontSize: 16,
|
||||||
|
logLevel: 0,
|
||||||
|
});
|
||||||
|
function callback() {
|
||||||
|
alert('It worked');
|
||||||
|
}
|
||||||
|
mermaid.parseError = function (err, hash) {
|
||||||
|
console.error('In parse error:');
|
||||||
|
console.error(err);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let coll = document.getElementsByClassName("collapsible");
|
||||||
|
for (const element of coll) {
|
||||||
|
element.addEventListener("click", function () {
|
||||||
|
this.classList.toggle("active");
|
||||||
|
let content = this.nextElementSibling;
|
||||||
|
if (content.style.maxHeight) {
|
||||||
|
content.style.maxHeight = null;
|
||||||
|
} else {
|
||||||
|
content.style.maxHeight = content.scrollHeight + "px";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
181
cypress/platform/flowchart-sate.html
Normal file
181
cypress/platform/flowchart-sate.html
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
<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" />
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Arial';
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
table-layout: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
border: 1px solid black;
|
||||||
|
padding: 10px;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator {
|
||||||
|
height: 20px;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-header {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapsible {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
color: #444;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 18px;
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
text-align: left;
|
||||||
|
outline: none;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active,
|
||||||
|
.collapsible:hover {
|
||||||
|
background-color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapsible:after {
|
||||||
|
content: '\002B';
|
||||||
|
color: #777;
|
||||||
|
font-weight: bold;
|
||||||
|
float: right;
|
||||||
|
margin-left: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active:after {
|
||||||
|
content: "\2212";
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 0 5px;
|
||||||
|
max-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: max-height 0.2s ease-out;
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content .pre-scrollable {
|
||||||
|
max-height: 200px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th></th> <!-- Placeholder for the top left corner -->
|
||||||
|
<th>State rough</th>
|
||||||
|
<th>Flowchart rough</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="vertical-header">
|
||||||
|
<button class="collapsible">Stadium shape</button>
|
||||||
|
<div class="content">
|
||||||
|
<div class="pre-scrollable">
|
||||||
|
<pre>
|
||||||
|
flowchart LR
|
||||||
|
id1([This is the text in the box])
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram1" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn"} }%%
|
||||||
|
stateDiagram-v2
|
||||||
|
stateA
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<pre id="diagram2" class="mermaid">
|
||||||
|
%%{init: {"look": "handdrawn"} }%%
|
||||||
|
flowchart LR
|
||||||
|
id1[[This is the text in the box]]
|
||||||
|
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
<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) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
mermaid.initialize({
|
||||||
|
handdrawn: false,
|
||||||
|
mergeEdges: true,
|
||||||
|
layout: 'dagre',
|
||||||
|
flowchart: { titleTopMargin: 10 },
|
||||||
|
// fontFamily: 'Caveat',
|
||||||
|
fontFamily: 'Kalam',
|
||||||
|
sequence: {
|
||||||
|
actorFontFamily: 'courier',
|
||||||
|
noteFontFamily: 'courier',
|
||||||
|
messageFontFamily: 'courier',
|
||||||
|
},
|
||||||
|
fontSize: 16,
|
||||||
|
logLevel: 0,
|
||||||
|
});
|
||||||
|
function callback() {
|
||||||
|
alert('It worked');
|
||||||
|
}
|
||||||
|
mermaid.parseError = function (err, hash) {
|
||||||
|
console.error('In parse error:');
|
||||||
|
console.error(err);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let coll = document.getElementsByClassName("collapsible");
|
||||||
|
for (const element of coll) {
|
||||||
|
element.addEventListener("click", function () {
|
||||||
|
this.classList.toggle("active");
|
||||||
|
let content = this.nextElementSibling;
|
||||||
|
if (content.style.maxHeight) {
|
||||||
|
content.style.maxHeight = null;
|
||||||
|
} else {
|
||||||
|
content.style.maxHeight = content.scrollHeight + "px";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@ -136,15 +136,19 @@ sequenceDiagram
|
|||||||
</pre
|
</pre
|
||||||
>
|
>
|
||||||
|
|
||||||
<pre id="diagram" class="mermaid">
|
<pre id="diagram" class="mermaid2">
|
||||||
%%{init: {"layout": "elk", "mergeEdges": true} }%%
|
%%{init: {"layout": "elk", "mergeEdges": true} }%%
|
||||||
stateDiagram
|
stateDiagram
|
||||||
direction TB
|
A --> B
|
||||||
T00 --> T0
|
|
||||||
T00 --> T1
|
|
||||||
</pre
|
</pre
|
||||||
>
|
>
|
||||||
<pre id="diagram" class="mermaid">
|
<pre id="diagram" class="mermaid">
|
||||||
|
%%{init: {"layout": "elk", "mergeEdges": true} }%%
|
||||||
|
flowchart
|
||||||
|
A --> B(This is B)
|
||||||
|
</pre
|
||||||
|
>
|
||||||
|
<pre id="diagram" class="mermaid2">
|
||||||
%%{init: {"layout": "elk", "mergeEdges": false, "elk.nodePlacement.strategy": "NETWORK_SIMPLEX"} }%%
|
%%{init: {"layout": "elk", "mergeEdges": false, "elk.nodePlacement.strategy": "NETWORK_SIMPLEX"} }%%
|
||||||
stateDiagram
|
stateDiagram
|
||||||
State T0 {
|
State T0 {
|
||||||
|
@ -1135,8 +1135,6 @@ export const insertNode = async (elem, node, dir) => {
|
|||||||
let newEl;
|
let newEl;
|
||||||
let el;
|
let el;
|
||||||
|
|
||||||
// console.log('insertNode element', elem, elem.node());
|
|
||||||
// debugger;
|
|
||||||
// Add link when appropriate
|
// Add link when appropriate
|
||||||
if (node.link) {
|
if (node.link) {
|
||||||
let target;
|
let target;
|
||||||
|
@ -2,6 +2,7 @@ import { select } from 'd3';
|
|||||||
import utils from '../../utils.js';
|
import utils from '../../utils.js';
|
||||||
import { getConfig, defaultConfig } from '../../diagram-api/diagramAPI.js';
|
import { getConfig, defaultConfig } from '../../diagram-api/diagramAPI.js';
|
||||||
import common from '../common/common.js';
|
import common from '../common/common.js';
|
||||||
|
import type { LayoutData, LayoutMethod, Node, Edge } from '../../rendering-util/types.js';
|
||||||
import { log } from '../../logger.js';
|
import { log } from '../../logger.js';
|
||||||
import {
|
import {
|
||||||
setAccTitle,
|
setAccTitle,
|
||||||
@ -755,11 +756,55 @@ export const lex = {
|
|||||||
firstGraph,
|
firstGraph,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getTypeFromVertex = (vertex: FlowVertex) => {
|
||||||
|
if (vertex.type === 'square') {
|
||||||
|
return 'squareRect';
|
||||||
|
}
|
||||||
|
if (vertex.type === 'round') {
|
||||||
|
return 'roundedRect';
|
||||||
|
}
|
||||||
|
|
||||||
|
return vertex.type || 'squareRect';
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getData = () => {
|
||||||
|
const config = getConfig();
|
||||||
|
const nodes: Node[] = [];
|
||||||
|
const edges: Edge[] = [];
|
||||||
|
|
||||||
|
// extract(getRootDocV2());
|
||||||
|
// const diagramStates = getStates();
|
||||||
|
const useRough = config.look === 'handdrawn';
|
||||||
|
const n = getVertices();
|
||||||
|
n.forEach((vertex) => {
|
||||||
|
const node: Node = {
|
||||||
|
id: vertex.id,
|
||||||
|
label: vertex.text,
|
||||||
|
labelStyle: '',
|
||||||
|
padding: config.flowchart?.padding || 8,
|
||||||
|
cssStyles: vertex.styles.join(' '),
|
||||||
|
cssClasses: vertex.classes.join(' '),
|
||||||
|
shape: getTypeFromVertex(vertex),
|
||||||
|
dir: vertex.dir,
|
||||||
|
domId: vertex.domId,
|
||||||
|
type: undefined,
|
||||||
|
isGroup: false,
|
||||||
|
useRough,
|
||||||
|
};
|
||||||
|
nodes.push(node);
|
||||||
|
});
|
||||||
|
|
||||||
|
//const useRough = config.look === 'handdrawn';
|
||||||
|
|
||||||
|
return { nodes, edges, other: {}, config };
|
||||||
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
defaultConfig: () => defaultConfig.flowchart,
|
defaultConfig: () => defaultConfig.flowchart,
|
||||||
setAccTitle,
|
setAccTitle,
|
||||||
getAccTitle,
|
getAccTitle,
|
||||||
getAccDescription,
|
getAccDescription,
|
||||||
|
getData,
|
||||||
setAccDescription,
|
setAccDescription,
|
||||||
addVertex,
|
addVertex,
|
||||||
lookUpDomId,
|
lookUpDomId,
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
// @ts-ignore: JISON doesn't support types
|
// @ts-ignore: JISON doesn't support types
|
||||||
import flowParser from './parser/flow.jison';
|
import flowParser from './parser/flow.jison';
|
||||||
import flowDb from './flowDb.js';
|
import flowDb from './flowDb.js';
|
||||||
import flowRendererV2 from './flowRenderer-v2.js';
|
// import flowRendererV2 from './flowRenderer-v2.js';
|
||||||
|
import flowRendererV3 from './flowRenderer-v3-unified.js';
|
||||||
import flowStyles from './styles.js';
|
import flowStyles from './styles.js';
|
||||||
import type { MermaidConfig } from '../../config.type.js';
|
import type { MermaidConfig } from '../../config.type.js';
|
||||||
import { setConfig } from '../../diagram-api/diagramAPI.js';
|
import { setConfig } from '../../diagram-api/diagramAPI.js';
|
||||||
@ -9,7 +10,8 @@ import { setConfig } from '../../diagram-api/diagramAPI.js';
|
|||||||
export const diagram = {
|
export const diagram = {
|
||||||
parser: flowParser,
|
parser: flowParser,
|
||||||
db: flowDb,
|
db: flowDb,
|
||||||
renderer: flowRendererV2,
|
// renderer: flowRendererV2,
|
||||||
|
renderer: flowRendererV3,
|
||||||
styles: flowStyles,
|
styles: flowStyles,
|
||||||
init: (cnf: MermaidConfig) => {
|
init: (cnf: MermaidConfig) => {
|
||||||
if (!cnf.flowchart) {
|
if (!cnf.flowchart) {
|
||||||
@ -18,7 +20,7 @@ export const diagram = {
|
|||||||
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||||
// flowchart-v2 uses dagre-wrapper, which doesn't have access to flowchart cnf
|
// flowchart-v2 uses dagre-wrapper, which doesn't have access to flowchart cnf
|
||||||
setConfig({ flowchart: { arrowMarkerAbsolute: cnf.arrowMarkerAbsolute } });
|
setConfig({ flowchart: { arrowMarkerAbsolute: cnf.arrowMarkerAbsolute } });
|
||||||
flowRendererV2.setConf(cnf.flowchart);
|
flowRendererV3.setConf(cnf.flowchart);
|
||||||
flowDb.clear();
|
flowDb.clear();
|
||||||
flowDb.setGen('gen-2');
|
flowDb.setGen('gen-2');
|
||||||
},
|
},
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
// @ts-ignore: JISON doesn't support types
|
||||||
|
import flowParser from './parser/flow.jison';
|
||||||
|
import flowDb from './flowDb.js';
|
||||||
|
import flowRendererV2 from './flowRenderer-v2.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,
|
||||||
|
styles: flowStyles,
|
||||||
|
init: (cnf: MermaidConfig) => {
|
||||||
|
if (!cnf.flowchart) {
|
||||||
|
cnf.flowchart = {};
|
||||||
|
}
|
||||||
|
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||||
|
// flowchart-v2 uses dagre-wrapper, which doesn't have access to flowchart cnf
|
||||||
|
setConfig({ flowchart: { arrowMarkerAbsolute: cnf.arrowMarkerAbsolute } });
|
||||||
|
flowRendererV2.setConf(cnf.flowchart);
|
||||||
|
flowDb.clear();
|
||||||
|
flowDb.setGen('gen-2');
|
||||||
|
},
|
||||||
|
};
|
@ -0,0 +1,81 @@
|
|||||||
|
import { log } from '../../logger.js';
|
||||||
|
import type { DiagramStyleClassDef } from '../../diagram-api/types.js';
|
||||||
|
import type { LayoutData, LayoutMethod } from '../../rendering-util/types.js';
|
||||||
|
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||||
|
import { render } from '../../rendering-util/render.js';
|
||||||
|
import { getDiagramElements } from '../../rendering-util/insertElementsForSize.js';
|
||||||
|
import { setupViewPortForSVG } from '../../rendering-util/setupViewPortForSVG.js';
|
||||||
|
import { getDirection } from './flowDb.js';
|
||||||
|
|
||||||
|
import utils from '../../utils.js';
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
const conf: Record<string, any> = {};
|
||||||
|
|
||||||
|
export const setConf = function (cnf: Record<string, any>) {
|
||||||
|
const keys = Object.keys(cnf);
|
||||||
|
for (const key of keys) {
|
||||||
|
conf[key] = cnf[key];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getClasses = function (
|
||||||
|
text: string,
|
||||||
|
diagramObj: any
|
||||||
|
): Record<string, DiagramStyleClassDef> {
|
||||||
|
// diagramObj.db.extract(diagramObj.db.getRootDocV2());
|
||||||
|
return diagramObj.db.getClasses();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const draw = async function (text: string, id: string, _version: string, diag: any) {
|
||||||
|
log.info('REF0:');
|
||||||
|
log.info('Drawing state diagram (v2)', id);
|
||||||
|
const { securityLevel, state: conf, layout } = getConfig();
|
||||||
|
|
||||||
|
const DIR = getDirection();
|
||||||
|
|
||||||
|
// The getData method provided in all supported diagrams is used to extract the data from the parsed structure
|
||||||
|
// into the Layout data format
|
||||||
|
console.log('Before getData: ');
|
||||||
|
const data4Layout = diag.db.getData() as LayoutData;
|
||||||
|
console.log('Data: ', data4Layout);
|
||||||
|
// Create the root SVG - the element is the div containing the SVG element
|
||||||
|
const { element, svg } = getDiagramElements(id, securityLevel);
|
||||||
|
|
||||||
|
// // For some diagrams this call is not needed, but in the state diagram it is
|
||||||
|
// await insertElementsForSize(element, data4Layout);
|
||||||
|
|
||||||
|
// console.log('data4Layout:', data4Layout);
|
||||||
|
|
||||||
|
// // Now we have layout data with real sizes, we can perform the layout
|
||||||
|
// const data4Rendering = doLayout(data4Layout, id, _version, 'dagre-wrapper');
|
||||||
|
|
||||||
|
// // The performRender method provided in all supported diagrams is used to render the data
|
||||||
|
// performRender(data4Rendering);
|
||||||
|
|
||||||
|
data4Layout.type = diag.type;
|
||||||
|
// data4Layout.layoutAlgorithm = 'dagre-wrapper';
|
||||||
|
// data4Layout.layoutAlgorithm = 'elk';
|
||||||
|
data4Layout.layoutAlgorithm = layout;
|
||||||
|
data4Layout.direction = DIR;
|
||||||
|
data4Layout.nodeSpacing = conf?.nodeSpacing || 50;
|
||||||
|
data4Layout.rankSpacing = conf?.rankSpacing || 50;
|
||||||
|
data4Layout.markers = ['barb'];
|
||||||
|
data4Layout.diagramId = id;
|
||||||
|
console.log('REF1:', data4Layout);
|
||||||
|
await render(data4Layout, svg, element);
|
||||||
|
const padding = 8;
|
||||||
|
utils.insertTitle(
|
||||||
|
element,
|
||||||
|
'statediagramTitleText',
|
||||||
|
conf?.titleTopMargin || 0,
|
||||||
|
diag.db.getDiagramTitle()
|
||||||
|
);
|
||||||
|
setupViewPortForSVG(svg, padding, 'flowchart', conf?.useMaxWidth || false);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setConf,
|
||||||
|
getClasses,
|
||||||
|
draw,
|
||||||
|
};
|
@ -585,6 +585,7 @@ export const getData = () => {
|
|||||||
const useRough = config.look === 'handdrawn';
|
const useRough = config.look === 'handdrawn';
|
||||||
dataFetcher(undefined, getRootDocV2(), diagramStates, nodes, edges, true, useRough);
|
dataFetcher(undefined, getRootDocV2(), diagramStates, nodes, edges, true, useRough);
|
||||||
|
|
||||||
|
console.log('State Nodes XDX:', nodes);
|
||||||
return { nodes, edges, other: {}, config };
|
return { nodes, edges, other: {}, config };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,6 +23,11 @@ export const getDiagramElements = (id, securityLevel) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// export function insertElementsForSize(el: SVGElement, data: LayoutData): void {
|
// export function insertElementsForSize(el: SVGElement, data: LayoutData): void {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param el
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
export function insertElementsForSize(el, data) {
|
export function insertElementsForSize(el, data) {
|
||||||
const nodesElem = el.insert('g').attr('class', 'nodes');
|
const nodesElem = el.insert('g').attr('class', 'nodes');
|
||||||
const edgesElem = el.insert('g').attr('class', 'edges');
|
const edgesElem = el.insert('g').attr('class', 'edges');
|
||||||
|
@ -1,12 +1,25 @@
|
|||||||
import { log } from '$root/logger.js';
|
import { log } from '$root/logger.js';
|
||||||
import { rect } from './shapes/rect.ts';
|
import { state } from './shapes/state.ts';
|
||||||
|
import { roundedRect } from './shapes/roundedRect.ts';
|
||||||
|
import { squareRect } from './shapes/squareRect.ts';
|
||||||
import { stateStart } from './shapes/stateStart.ts';
|
import { stateStart } from './shapes/stateStart.ts';
|
||||||
import { stateEnd } from './shapes/stateEnd.ts';
|
import { stateEnd } from './shapes/stateEnd.ts';
|
||||||
import { forkJoin } from './shapes/forkJoin.ts';
|
import { forkJoin } from './shapes/forkJoin.ts';
|
||||||
import { choice } from './shapes/choice.ts';
|
import { choice } from './shapes/choice.ts';
|
||||||
import { note } from './shapes/note.ts';
|
import { note } from './shapes/note.ts';
|
||||||
|
import { stadium } from './shapes/stadium.js';
|
||||||
import { getConfig } from '$root/diagram-api/diagramAPI.js';
|
import { getConfig } from '$root/diagram-api/diagramAPI.js';
|
||||||
|
import { subroutine } from './shapes/subroutine.js';
|
||||||
|
import { cylinder } from './shapes/cylinder.js';
|
||||||
|
import { circle } from './shapes/circle.js';
|
||||||
|
import { doublecircle } from './shapes/doubleCircle.js';
|
||||||
|
import { rect_left_inv_arrow } from './shapes/rectLeftInvArrow.js';
|
||||||
|
import { question } from './shapes/question.js';
|
||||||
|
import { hexagon } from './shapes/hexagon.js';
|
||||||
|
import { lean_right } from './shapes/leanRight.js';
|
||||||
|
import { lean_left } from './shapes/leanLeft.js';
|
||||||
|
import { trapezoid } from './shapes/trapezoid.js';
|
||||||
|
import { inv_trapezoid } from './shapes/invertedTrapezoid.js';
|
||||||
const formatClass = (str) => {
|
const formatClass = (str) => {
|
||||||
if (str) {
|
if (str) {
|
||||||
return ' ' + str;
|
return ' ' + str;
|
||||||
@ -15,13 +28,27 @@ const formatClass = (str) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const shapes = {
|
const shapes = {
|
||||||
rect,
|
state,
|
||||||
stateStart,
|
stateStart,
|
||||||
stateEnd,
|
stateEnd,
|
||||||
fork: forkJoin,
|
fork: forkJoin,
|
||||||
join: forkJoin,
|
join: forkJoin,
|
||||||
choice,
|
choice,
|
||||||
note,
|
note,
|
||||||
|
roundedRect,
|
||||||
|
squareRect,
|
||||||
|
stadium,
|
||||||
|
subroutine,
|
||||||
|
cylinder,
|
||||||
|
circle,
|
||||||
|
doublecircle,
|
||||||
|
odd: rect_left_inv_arrow,
|
||||||
|
diamond: question,
|
||||||
|
hexagon,
|
||||||
|
lean_right,
|
||||||
|
lean_left,
|
||||||
|
trapezoid,
|
||||||
|
inv_trapezoid,
|
||||||
};
|
};
|
||||||
|
|
||||||
let nodeElems = {};
|
let nodeElems = {};
|
||||||
@ -30,7 +57,18 @@ export const insertNode = async (elem, node, dir) => {
|
|||||||
let newEl;
|
let newEl;
|
||||||
let el;
|
let el;
|
||||||
|
|
||||||
// debugger;
|
if (node) {
|
||||||
|
console.log('BLA: rect node', JSON.stringify(node));
|
||||||
|
}
|
||||||
|
//special check for rect shape (with or without rounded corners)
|
||||||
|
if (node.shape === 'rect') {
|
||||||
|
if (node.rx && node.ry) {
|
||||||
|
node.shape = 'roundedRect';
|
||||||
|
} else {
|
||||||
|
node.shape = 'squareRect';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add link when appropriate
|
// Add link when appropriate
|
||||||
if (node.link) {
|
if (node.link) {
|
||||||
let target;
|
let target;
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
import { log } from '$root/logger.js';
|
||||||
|
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
|
||||||
|
import intersect from '../intersect/index.js';
|
||||||
|
import type { Node } from '$root/rendering-util/types.d.ts';
|
||||||
|
import { userNodeOverrides } from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
|
||||||
|
import rough from 'roughjs';
|
||||||
|
|
||||||
|
export const circle = async (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
|
||||||
|
const { shapeSvg, bbox, halfPadding } = await labelHelper(
|
||||||
|
parent,
|
||||||
|
node,
|
||||||
|
getNodeClasses(node),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
const radius = bbox.width / 2 + halfPadding;
|
||||||
|
let circleElem;
|
||||||
|
const { cssStyles, useRough } = node;
|
||||||
|
|
||||||
|
if (useRough) {
|
||||||
|
// @ts-ignore
|
||||||
|
const rc = rough.svg(shapeSvg);
|
||||||
|
const options = userNodeOverrides(node, {});
|
||||||
|
const roughNode = rc.circle(0, 0, radius * 2, options);
|
||||||
|
|
||||||
|
circleElem = shapeSvg.insert(() => roughNode, ':first-child');
|
||||||
|
circleElem.attr('class', 'basic label-container').attr('style', cssStyles);
|
||||||
|
} else {
|
||||||
|
circleElem = shapeSvg
|
||||||
|
.insert('circle', ':first-child')
|
||||||
|
.attr('class', 'basic label-container')
|
||||||
|
.attr('style', cssStyles)
|
||||||
|
.attr('r', radius)
|
||||||
|
.attr('cx', 0)
|
||||||
|
.attr('cy', 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateNodeBounds(node, circleElem);
|
||||||
|
|
||||||
|
node.intersect = function (point) {
|
||||||
|
log.info('Circle intersect', node, radius, point);
|
||||||
|
return intersect.circle(node, radius, point);
|
||||||
|
};
|
||||||
|
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
@ -0,0 +1,127 @@
|
|||||||
|
import { log } from '$root/logger.js';
|
||||||
|
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
|
||||||
|
import intersect from '../intersect/index.js';
|
||||||
|
import type { Node } from '$root/rendering-util/types.d.ts';
|
||||||
|
import { userNodeOverrides } from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
|
||||||
|
import rough from 'roughjs';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an SVG path for a cylindrical shape.
|
||||||
|
* @param {number} x - The x coordinate of the top-left corner.
|
||||||
|
* @param {number} y - The y coordinate of the top-left corner.
|
||||||
|
* @param {number} width - The width of the cylinder.
|
||||||
|
* @param {number} height - The height of the cylinder.
|
||||||
|
* @param {number} rx - The x-radius of the cylinder's ends.
|
||||||
|
* @param {number} ry - The y-radius of the cylinder's ends.
|
||||||
|
* @returns {string} The path data for the cylindrical shape.
|
||||||
|
*/
|
||||||
|
export const createCylinderPathD = (
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
rx: number,
|
||||||
|
ry: 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}`,
|
||||||
|
].join(' ');
|
||||||
|
};
|
||||||
|
export const createOuterCylinderPathD = (
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
rx: number,
|
||||||
|
ry: number
|
||||||
|
): string => {
|
||||||
|
return [
|
||||||
|
`M${x},${y + ry}`,
|
||||||
|
`M${x + width},${y + ry}`,
|
||||||
|
`a${rx},${ry} 0,0,0 ${-width},0`,
|
||||||
|
`l0,${height}`,
|
||||||
|
`a${rx},${ry} 0,0,0 ${width},0`,
|
||||||
|
`l0,${-height}`,
|
||||||
|
].join(' ');
|
||||||
|
};
|
||||||
|
export const createInnerCylinderPathD = (
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
rx: number,
|
||||||
|
ry: number
|
||||||
|
): string => {
|
||||||
|
return [`M${x - width / 2},${-height / 2}`, `a${rx},${ry} 0,0,0 ${width},0`].join(' ');
|
||||||
|
};
|
||||||
|
export const cylinder = async (parent: SVGAElement, node: Node) => {
|
||||||
|
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node), true);
|
||||||
|
|
||||||
|
const w = bbox.width + node.padding;
|
||||||
|
const rx = w / 2;
|
||||||
|
const ry = rx / (2.5 + w / 50);
|
||||||
|
const h = bbox.height + ry + node.padding;
|
||||||
|
|
||||||
|
let cylinder: d3.Selection<SVGPathElement | SVGGElement, unknown, null, undefined>;
|
||||||
|
const { cssStyles, useRough } = node;
|
||||||
|
|
||||||
|
if (useRough) {
|
||||||
|
// @ts-ignore
|
||||||
|
const rc = rough.svg(shapeSvg);
|
||||||
|
const outerPathData = createOuterCylinderPathD(0, 0, w, h, rx, ry);
|
||||||
|
const innerPathData = createInnerCylinderPathD(0, ry, w, h, rx, ry);
|
||||||
|
const outerNode = rc.path(outerPathData, userNodeOverrides(node, {}));
|
||||||
|
const innerLine = rc.path(innerPathData, userNodeOverrides(node, { fill: 'none' }));
|
||||||
|
|
||||||
|
cylinder = shapeSvg.insert(() => innerLine, ':first-child');
|
||||||
|
cylinder = shapeSvg.insert(() => outerNode, ':first-child');
|
||||||
|
cylinder.attr('class', 'basic label-container');
|
||||||
|
if (cssStyles) {
|
||||||
|
cylinder.attr('style', cssStyles);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const pathData = createCylinderPathD(0, 0, w, h, rx, ry);
|
||||||
|
cylinder = shapeSvg
|
||||||
|
.insert('path', ':first-child')
|
||||||
|
.attr('d', pathData)
|
||||||
|
.attr('class', 'basic label-container')
|
||||||
|
.attr('style', cssStyles);
|
||||||
|
}
|
||||||
|
|
||||||
|
cylinder.attr('label-offset-y', ry);
|
||||||
|
cylinder.attr('transform', `translate(${-w / 2}, ${-(h / 2 + ry)})`);
|
||||||
|
|
||||||
|
updateNodeBounds(node, cylinder);
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
@ -0,0 +1,68 @@
|
|||||||
|
import { log } from '$root/logger.js';
|
||||||
|
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
|
||||||
|
import intersect from '../intersect/index.js';
|
||||||
|
import type { Node } from '$root/rendering-util/types.d.ts';
|
||||||
|
import { userNodeOverrides } from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
|
||||||
|
import rough from 'roughjs';
|
||||||
|
//import d3 from 'd3';
|
||||||
|
|
||||||
|
export const doublecircle = async (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
|
||||||
|
const { shapeSvg, bbox, halfPadding } = await labelHelper(
|
||||||
|
parent,
|
||||||
|
node,
|
||||||
|
getNodeClasses(node),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
const gap = 5;
|
||||||
|
const outerRadius = bbox.width / 2 + halfPadding + gap;
|
||||||
|
const innerRadius = bbox.width / 2 + halfPadding;
|
||||||
|
|
||||||
|
let circleGroup;
|
||||||
|
const { cssStyles, useRough } = node;
|
||||||
|
|
||||||
|
if (useRough) {
|
||||||
|
// @ts-ignore
|
||||||
|
const rc = rough.svg(shapeSvg);
|
||||||
|
const outerOptions = userNodeOverrides(node, { roughness: 0.2, strokeWidth: 2.5 });
|
||||||
|
|
||||||
|
const innerOptions = userNodeOverrides(node, { roughness: 0.2, strokeWidth: 1.5 });
|
||||||
|
const outerRoughNode = rc.circle(0, 0, outerRadius * 2, outerOptions);
|
||||||
|
const innerRoughNode = rc.circle(0, 0, innerRadius * 2, innerOptions);
|
||||||
|
|
||||||
|
circleGroup = shapeSvg.insert('g', ':first-child');
|
||||||
|
// circleGroup = circleGroup.insert(() => outerRoughNode, ':first-child');
|
||||||
|
circleGroup.attr('class', node.cssClasses).attr('style', cssStyles);
|
||||||
|
|
||||||
|
circleGroup.node()?.appendChild(outerRoughNode);
|
||||||
|
circleGroup.node()?.appendChild(innerRoughNode);
|
||||||
|
} else {
|
||||||
|
circleGroup = shapeSvg.insert('g', ':first-child');
|
||||||
|
const outerCircle = circleGroup.insert('circle', ':first-child');
|
||||||
|
const innerCircle = circleGroup.insert('circle', ':first-child');
|
||||||
|
|
||||||
|
circleGroup.attr('class', 'basic label-container').attr('style', cssStyles);
|
||||||
|
|
||||||
|
outerCircle
|
||||||
|
.attr('class', 'outer-circle')
|
||||||
|
.attr('style', cssStyles)
|
||||||
|
.attr('r', outerRadius)
|
||||||
|
.attr('cx', 0)
|
||||||
|
.attr('cy', 0);
|
||||||
|
|
||||||
|
innerCircle
|
||||||
|
.attr('class', 'inner-circle')
|
||||||
|
.attr('style', cssStyles)
|
||||||
|
.attr('r', innerRadius)
|
||||||
|
.attr('cx', 0)
|
||||||
|
.attr('cy', 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateNodeBounds(node, circleGroup);
|
||||||
|
|
||||||
|
node.intersect = function (point) {
|
||||||
|
log.info('DoubleCircle intersect', node, outerRadius, point);
|
||||||
|
return intersect.circle(node, outerRadius, point);
|
||||||
|
};
|
||||||
|
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
@ -1,64 +1,16 @@
|
|||||||
import { log } from '$root/logger.js';
|
import { log } from '$root/logger.js';
|
||||||
import { labelHelper, updateNodeBounds } from './util.js';
|
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
|
||||||
import intersect from '../intersect/index.js';
|
import intersect from '../intersect/index.js';
|
||||||
import type { Node } from '$root/rendering-util/types.d.ts';
|
import type { Node, RectOptions } from '$root/rendering-util/types.d.ts';
|
||||||
import { createRoundedRectPathD } from './roundedRectPath.js';
|
import { createRoundedRectPathD } from './roundedRectPath.js';
|
||||||
import { getConfig } from '$root/diagram-api/diagramAPI.js';
|
|
||||||
import { userNodeOverrides } from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
|
import { userNodeOverrides } from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
|
||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
|
|
||||||
// function applyNodePropertyBorders(
|
export const drawRect = async (parent: SVGAElement, node: Node, options: RectOptions) => {
|
||||||
// rect: d3.Selection<SVGRectElement, unknown, null, undefined>,
|
|
||||||
// borders: string | undefined,
|
|
||||||
// totalWidth: number,
|
|
||||||
// totalHeight: number
|
|
||||||
// ) {
|
|
||||||
// if (!borders) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// const strokeDashArray: number[] = [];
|
|
||||||
// const addBorder = (length: number) => {
|
|
||||||
// strokeDashArray.push(length, 0);
|
|
||||||
// };
|
|
||||||
// const skipBorder = (length: number) => {
|
|
||||||
// strokeDashArray.push(0, length);
|
|
||||||
// };
|
|
||||||
// if (borders.includes('t')) {
|
|
||||||
// log.debug('add top border');
|
|
||||||
// addBorder(totalWidth);
|
|
||||||
// } else {
|
|
||||||
// skipBorder(totalWidth);
|
|
||||||
// }
|
|
||||||
// if (borders.includes('r')) {
|
|
||||||
// log.debug('add right border');
|
|
||||||
// addBorder(totalHeight);
|
|
||||||
// } else {
|
|
||||||
// skipBorder(totalHeight);
|
|
||||||
// }
|
|
||||||
// if (borders.includes('b')) {
|
|
||||||
// log.debug('add bottom border');
|
|
||||||
// addBorder(totalWidth);
|
|
||||||
// } else {
|
|
||||||
// skipBorder(totalWidth);
|
|
||||||
// }
|
|
||||||
// if (borders.includes('l')) {
|
|
||||||
// log.debug('add left border');
|
|
||||||
// addBorder(totalHeight);
|
|
||||||
// } else {
|
|
||||||
// skipBorder(totalHeight);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// rect.attr('stroke-dasharray', strokeDashArray.join(' '));
|
|
||||||
// }
|
|
||||||
|
|
||||||
export const rect = async (parent: SVGAElement, node: Node) => {
|
|
||||||
const { themeVariables, handdrawnSeed } = getConfig();
|
|
||||||
const { nodeBorder, mainBkg } = themeVariables;
|
|
||||||
|
|
||||||
const { shapeSvg, bbox, halfPadding } = await labelHelper(
|
const { shapeSvg, bbox, halfPadding } = await labelHelper(
|
||||||
parent,
|
parent,
|
||||||
node,
|
node,
|
||||||
'node ' + node.cssClasses, // + ' ' + node.class,
|
getNodeClasses(node),
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -68,19 +20,20 @@ export const rect = async (parent: SVGAElement, node: Node) => {
|
|||||||
const y = -bbox.height / 2 - halfPadding;
|
const y = -bbox.height / 2 - halfPadding;
|
||||||
|
|
||||||
let rect;
|
let rect;
|
||||||
const { rx, ry, cssStyles, useRough } = node;
|
let { rx, ry, cssStyles, useRough } = node;
|
||||||
|
|
||||||
|
//use options rx, ry overrides if present
|
||||||
|
if (options && options.rx && options.ry) {
|
||||||
|
rx = options.rx;
|
||||||
|
ry = options.ry;
|
||||||
|
}
|
||||||
|
|
||||||
if (useRough) {
|
if (useRough) {
|
||||||
// @ts-ignore TODO: Fix rough typings
|
// @ts-ignore TODO: Fix rough typings
|
||||||
const rc = rough.svg(shapeSvg);
|
const rc = rough.svg(shapeSvg);
|
||||||
const options = userNodeOverrides(node, {
|
const options = userNodeOverrides(node, {});
|
||||||
roughness: 0.7,
|
|
||||||
fill: mainBkg,
|
console.log('rect options: ', options);
|
||||||
// fillStyle: 'solid', // solid fill'
|
|
||||||
fillStyle: 'hachure', // solid fill'
|
|
||||||
fillWeight: 3.5,
|
|
||||||
stroke: nodeBorder,
|
|
||||||
seed: handdrawnSeed,
|
|
||||||
});
|
|
||||||
const roughNode =
|
const roughNode =
|
||||||
rx || ry
|
rx || ry
|
||||||
? rc.path(createRoundedRectPathD(x, y, totalWidth, totalHeight, rx || 0), options)
|
? rc.path(createRoundedRectPathD(x, y, totalWidth, totalHeight, rx || 0), options)
|
||||||
@ -95,6 +48,8 @@ export const rect = async (parent: SVGAElement, node: Node) => {
|
|||||||
.attr('class', 'basic label-container')
|
.attr('class', 'basic label-container')
|
||||||
.attr('style', cssStyles)
|
.attr('style', cssStyles)
|
||||||
.attr('rx', rx)
|
.attr('rx', rx)
|
||||||
|
.attr('data-id', 'abc')
|
||||||
|
.attr('data-et', 'node')
|
||||||
.attr('ry', ry)
|
.attr('ry', ry)
|
||||||
.attr('x', x)
|
.attr('x', x)
|
||||||
.attr('y', y)
|
.attr('y', y)
|
@ -18,8 +18,25 @@ export const solidStateFill = (color: string) => {
|
|||||||
// Striped fill like start or fork nodes in state diagrams
|
// Striped fill like start or fork nodes in state diagrams
|
||||||
// TODO remove any
|
// TODO remove any
|
||||||
export const userNodeOverrides = (node: Node, options: any) => {
|
export const userNodeOverrides = (node: Node, options: any) => {
|
||||||
const result = Object.assign({}, options);
|
const { themeVariables, handdrawnSeed } = getConfig();
|
||||||
result.fill = node.backgroundColor || options.fill;
|
const { nodeBorder, mainBkg } = themeVariables;
|
||||||
result.stroke = node.borderColor || options.stroke;
|
const result = Object.assign(
|
||||||
|
{
|
||||||
|
roughness: 0.7,
|
||||||
|
fill: mainBkg,
|
||||||
|
fillStyle: 'hachure', // solid fill
|
||||||
|
fillWeight: 3.5,
|
||||||
|
stroke: nodeBorder,
|
||||||
|
seed: handdrawnSeed,
|
||||||
|
strokeWidth: 1.3,
|
||||||
|
},
|
||||||
|
options
|
||||||
|
);
|
||||||
|
if (node.backgroundColor) {
|
||||||
|
result.fill = node.backgroundColor;
|
||||||
|
}
|
||||||
|
if (node.borderColor) {
|
||||||
|
result.stroke = node.borderColor;
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,93 @@
|
|||||||
|
import { log } from '$root/logger.js';
|
||||||
|
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
|
||||||
|
import intersect from '../intersect/index.js';
|
||||||
|
import type { Node } from '$root/rendering-util/types.d.ts';
|
||||||
|
import { userNodeOverrides } from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
|
||||||
|
import rough from 'roughjs';
|
||||||
|
|
||||||
|
import { insertPolygonShape } from './insertPolygonShape.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an SVG path for a hexagon shape.
|
||||||
|
* @param {number} x - The x coordinate of the top-left corner.
|
||||||
|
* @param {number} y - The y coordinate of the top-left corner.
|
||||||
|
* @param {number} width - The width of the hexagon.
|
||||||
|
* @param {number} height - The height of the hexagon.
|
||||||
|
* @param {number} m - The margin size for the hexagon.
|
||||||
|
* @returns {string} The path data for the hexagon shape.
|
||||||
|
*/
|
||||||
|
export const createHexagonPathD = (
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
m: number
|
||||||
|
): string => {
|
||||||
|
return [
|
||||||
|
`M${x + m},${y}`,
|
||||||
|
`L${x + width - m},${y}`,
|
||||||
|
`L${x + width},${y - height / 2}`,
|
||||||
|
`L${x + width - m},${y - height}`,
|
||||||
|
`L${x + m},${y - height}`,
|
||||||
|
`L${x},${y - height / 2}`,
|
||||||
|
'Z',
|
||||||
|
].join(' ');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const hexagon = async (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
|
||||||
|
const { shapeSvg, bbox, halfPadding } = await labelHelper(
|
||||||
|
parent,
|
||||||
|
node,
|
||||||
|
getNodeClasses(node),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
const f = 4;
|
||||||
|
const h = bbox.height + node.padding;
|
||||||
|
const m = h / f;
|
||||||
|
const w = bbox.width + 2 * m + node.padding;
|
||||||
|
const points = [
|
||||||
|
{ x: m, y: 0 },
|
||||||
|
{ x: w - m, y: 0 },
|
||||||
|
{ x: w, y: -h / 2 },
|
||||||
|
{ x: w - m, y: -h },
|
||||||
|
{ x: m, y: -h },
|
||||||
|
{ x: 0, y: -h / 2 },
|
||||||
|
];
|
||||||
|
|
||||||
|
let polygon: d3.Selection<SVGPolygonElement | SVGGElement, unknown, null, undefined>;
|
||||||
|
const { cssStyles, useRough } = node;
|
||||||
|
|
||||||
|
if (useRough) {
|
||||||
|
// @ts-ignore
|
||||||
|
const rc = rough.svg(shapeSvg);
|
||||||
|
const options = userNodeOverrides(node, {});
|
||||||
|
const pathData = createHexagonPathD(0, 0, w, h, m);
|
||||||
|
const roughNode = rc.path(pathData, options);
|
||||||
|
|
||||||
|
polygon = shapeSvg
|
||||||
|
.insert(() => roughNode, ':first-child')
|
||||||
|
.attr('transform', `translate(${-w / 2}, ${h / 2})`);
|
||||||
|
|
||||||
|
if (cssStyles) {
|
||||||
|
polygon.attr('style', cssStyles);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
polygon = insertPolygonShape(shapeSvg, w, h, points);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cssStyles) {
|
||||||
|
polygon.attr('style', cssStyles);
|
||||||
|
}
|
||||||
|
|
||||||
|
node.width = w;
|
||||||
|
node.height = h;
|
||||||
|
|
||||||
|
updateNodeBounds(node, polygon);
|
||||||
|
|
||||||
|
node.intersect = function (point) {
|
||||||
|
return intersect.polygon(node, points, point);
|
||||||
|
};
|
||||||
|
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* @param parent
|
||||||
|
* @param w
|
||||||
|
* @param h
|
||||||
|
* @param points
|
||||||
|
*/
|
||||||
|
export function insertPolygonShape(
|
||||||
|
parent: any,
|
||||||
|
w: number,
|
||||||
|
h: number,
|
||||||
|
points: { x: number; y: number }[]
|
||||||
|
) {
|
||||||
|
return parent
|
||||||
|
.insert('polygon', ':first-child')
|
||||||
|
.attr(
|
||||||
|
'points',
|
||||||
|
points
|
||||||
|
.map(function (d) {
|
||||||
|
return d.x + ',' + d.y;
|
||||||
|
})
|
||||||
|
.join(' ')
|
||||||
|
)
|
||||||
|
.attr('class', 'label-container')
|
||||||
|
.attr('transform', 'translate(' + -w / 2 + ',' + h / 2 + ')');
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
import { log } from '$root/logger.js';
|
||||||
|
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
|
||||||
|
import intersect from '../intersect/index.js';
|
||||||
|
import { getConfig } from '$root/diagram-api/diagramAPI.js';
|
||||||
|
import type { Node } from '$root/rendering-util/types.d.ts';
|
||||||
|
import { userNodeOverrides } from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
|
||||||
|
import rough from 'roughjs';
|
||||||
|
import { insertPolygonShape } from './insertPolygonShape.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an SVG path for an inverted trapezoid shape.
|
||||||
|
* @param {number} x - The x coordinate of the top-left corner.
|
||||||
|
* @param {number} y - The y coordinate of the top-left corner.
|
||||||
|
* @param {number} width - The width of the shape.
|
||||||
|
* @param {number} height - The height of the shape.
|
||||||
|
* @returns {string} The path data for the inverted trapezoid shape.
|
||||||
|
*/
|
||||||
|
export const createInvertedTrapezoidPathD = (
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
width: number,
|
||||||
|
height: number
|
||||||
|
): string => {
|
||||||
|
return [
|
||||||
|
`M${x + height / 6},${y}`,
|
||||||
|
`L${x + width - height / 6},${y}`,
|
||||||
|
`L${x + width + (2 * height) / 6},${y - height}`,
|
||||||
|
`L${x - (2 * height) / 6},${y - height}`,
|
||||||
|
'Z',
|
||||||
|
].join(' ');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const inv_trapezoid = async (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
|
||||||
|
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node), true);
|
||||||
|
|
||||||
|
const w = bbox.width + node.padding;
|
||||||
|
const h = bbox.height + node.padding;
|
||||||
|
const points = [
|
||||||
|
{ x: h / 6, y: 0 },
|
||||||
|
{ x: w - h / 6, y: 0 },
|
||||||
|
{ x: w + (2 * h) / 6, y: -h },
|
||||||
|
{ x: (-2 * h) / 6, y: -h },
|
||||||
|
];
|
||||||
|
|
||||||
|
let polygon: d3.Selection<SVGPolygonElement | SVGGElement, unknown, null, undefined>;
|
||||||
|
const { cssStyles, useRough } = node;
|
||||||
|
|
||||||
|
if (useRough) {
|
||||||
|
// @ts-ignore
|
||||||
|
const rc = rough.svg(shapeSvg);
|
||||||
|
const options = userNodeOverrides(node, {});
|
||||||
|
const pathData = createInvertedTrapezoidPathD(0, 0, w, h);
|
||||||
|
const roughNode = rc.path(pathData, options);
|
||||||
|
|
||||||
|
polygon = shapeSvg
|
||||||
|
.insert(() => roughNode, ':first-child')
|
||||||
|
.attr('transform', `translate(${-w / 2}, ${h / 2})`);
|
||||||
|
|
||||||
|
if (cssStyles) {
|
||||||
|
polygon.attr('style', cssStyles);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
polygon = insertPolygonShape(shapeSvg, w, h, points);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cssStyles) {
|
||||||
|
polygon.attr('style', cssStyles);
|
||||||
|
}
|
||||||
|
|
||||||
|
node.width = w;
|
||||||
|
node.height = h;
|
||||||
|
|
||||||
|
updateNodeBounds(node, polygon);
|
||||||
|
|
||||||
|
node.intersect = function (point) {
|
||||||
|
return intersect.polygon(node, points, point);
|
||||||
|
};
|
||||||
|
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
@ -0,0 +1,79 @@
|
|||||||
|
import { log } from '$root/logger.js';
|
||||||
|
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
|
||||||
|
import intersect from '../intersect/index.js';
|
||||||
|
import type { Node } from '$root/rendering-util/types.d.ts';
|
||||||
|
import { userNodeOverrides } from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
|
||||||
|
import rough from 'roughjs';
|
||||||
|
import { insertPolygonShape } from './insertPolygonShape.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an SVG path for a lean left shape.
|
||||||
|
* @param {number} x - The x coordinate of the top-left corner.
|
||||||
|
* @param {number} y - The y coordinate of the top-left corner.
|
||||||
|
* @param {number} width - The width of the shape.
|
||||||
|
* @param {number} height - The height of the shape.
|
||||||
|
* @returns {string} The path data for the lean left shape.
|
||||||
|
*/
|
||||||
|
export const createLeanLeftPathD = (
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
width: number,
|
||||||
|
height: number
|
||||||
|
): string => {
|
||||||
|
return [
|
||||||
|
`M${x + (2 * height) / 6},${y}`,
|
||||||
|
`L${x + width + height / 6},${y}`,
|
||||||
|
`L${x + width - (2 * height) / 6},${y - height}`,
|
||||||
|
`L${x - height / 6},${y - height}`,
|
||||||
|
'Z',
|
||||||
|
].join(' ');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const lean_left = async (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
|
||||||
|
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node), true);
|
||||||
|
|
||||||
|
const w = bbox.width + node.padding;
|
||||||
|
const h = bbox.height + node.padding;
|
||||||
|
const points = [
|
||||||
|
{ x: (2 * h) / 6, y: 0 },
|
||||||
|
{ x: w + h / 6, y: 0 },
|
||||||
|
{ x: w - (2 * h) / 6, y: -h },
|
||||||
|
{ x: -h / 6, y: -h },
|
||||||
|
];
|
||||||
|
|
||||||
|
let polygon: d3.Selection<SVGPolygonElement | SVGGElement, unknown, null, undefined>;
|
||||||
|
const { cssStyles, useRough } = node;
|
||||||
|
|
||||||
|
if (useRough) {
|
||||||
|
// @ts-ignore
|
||||||
|
const rc = rough.svg(shapeSvg);
|
||||||
|
const options = userNodeOverrides(node, {});
|
||||||
|
const pathData = createLeanLeftPathD(0, 0, w, h);
|
||||||
|
const roughNode = rc.path(pathData, options);
|
||||||
|
|
||||||
|
polygon = shapeSvg
|
||||||
|
.insert(() => roughNode, ':first-child')
|
||||||
|
.attr('transform', `translate(${-w / 2}, ${h / 2})`);
|
||||||
|
|
||||||
|
if (cssStyles) {
|
||||||
|
polygon.attr('style', cssStyles);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
polygon = insertPolygonShape(shapeSvg, w, h, points);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cssStyles) {
|
||||||
|
polygon.attr('style', cssStyles);
|
||||||
|
}
|
||||||
|
|
||||||
|
node.width = w;
|
||||||
|
node.height = h;
|
||||||
|
|
||||||
|
updateNodeBounds(node, polygon);
|
||||||
|
|
||||||
|
node.intersect = function (point) {
|
||||||
|
return intersect.polygon(node, points, point);
|
||||||
|
};
|
||||||
|
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
@ -0,0 +1,79 @@
|
|||||||
|
import { log } from '$root/logger.js';
|
||||||
|
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
|
||||||
|
import intersect from '../intersect/index.js';
|
||||||
|
import type { Node } from '$root/rendering-util/types.d.ts';
|
||||||
|
import { userNodeOverrides } from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
|
||||||
|
import rough from 'roughjs';
|
||||||
|
import { insertPolygonShape } from './insertPolygonShape.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an SVG path for a lean right shape.
|
||||||
|
* @param {number} x - The x coordinate of the top-left corner.
|
||||||
|
* @param {number} y - The y coordinate of the top-left corner.
|
||||||
|
* @param {number} width - The width of the shape.
|
||||||
|
* @param {number} height - The height of the shape.
|
||||||
|
* @returns {string} The path data for the lean right shape.
|
||||||
|
*/
|
||||||
|
export const createLeanRightPathD = (
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
width: number,
|
||||||
|
height: number
|
||||||
|
): string => {
|
||||||
|
return [
|
||||||
|
`M${x - (2 * height) / 6},${y}`,
|
||||||
|
`L${x + width - height / 6},${y}`,
|
||||||
|
`L${x + width + (2 * height) / 6},${y - height}`,
|
||||||
|
`L${x + height / 6},${y - height}`,
|
||||||
|
'Z',
|
||||||
|
].join(' ');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const lean_right = async (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
|
||||||
|
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node), true);
|
||||||
|
|
||||||
|
const w = bbox.width + node.padding;
|
||||||
|
const h = bbox.height + node.padding;
|
||||||
|
const points = [
|
||||||
|
{ x: (-2 * h) / 6, y: 0 },
|
||||||
|
{ x: w - h / 6, y: 0 },
|
||||||
|
{ x: w + (2 * h) / 6, y: -h },
|
||||||
|
{ x: h / 6, y: -h },
|
||||||
|
];
|
||||||
|
|
||||||
|
let polygon: d3.Selection<SVGPolygonElement | SVGGElement, unknown, null, undefined>;
|
||||||
|
const { cssStyles, useRough } = node;
|
||||||
|
|
||||||
|
if (useRough) {
|
||||||
|
// @ts-ignore
|
||||||
|
const rc = rough.svg(shapeSvg);
|
||||||
|
const options = userNodeOverrides(node, {});
|
||||||
|
const pathData = createLeanRightPathD(0, 0, w, h);
|
||||||
|
const roughNode = rc.path(pathData, options);
|
||||||
|
|
||||||
|
polygon = shapeSvg
|
||||||
|
.insert(() => roughNode, ':first-child')
|
||||||
|
.attr('transform', `translate(${-w / 2}, ${h / 2})`);
|
||||||
|
|
||||||
|
if (cssStyles) {
|
||||||
|
polygon.attr('style', cssStyles);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
polygon = insertPolygonShape(shapeSvg, w, h, points);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cssStyles) {
|
||||||
|
polygon.attr('style', cssStyles);
|
||||||
|
}
|
||||||
|
|
||||||
|
node.width = w;
|
||||||
|
node.height = h;
|
||||||
|
|
||||||
|
updateNodeBounds(node, polygon);
|
||||||
|
|
||||||
|
node.intersect = function (point) {
|
||||||
|
return intersect.polygon(node, points, point);
|
||||||
|
};
|
||||||
|
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
@ -0,0 +1,73 @@
|
|||||||
|
import { log } from '$root/logger.js';
|
||||||
|
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
|
||||||
|
import intersect from '../intersect/index.js';
|
||||||
|
import type { Node } from '$root/rendering-util/types.d.ts';
|
||||||
|
import { userNodeOverrides } from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
|
||||||
|
import rough from 'roughjs';
|
||||||
|
import { insertPolygonShape } from './insertPolygonShape.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an SVG path for a decision box shape (question shape).
|
||||||
|
* @param {number} x - The x coordinate of the top-left corner.
|
||||||
|
* @param {number} y - The y coordinate of the top-left corner.
|
||||||
|
* @param {number} size - The size of the shape.
|
||||||
|
* @returns {string} The path data for the decision box shape.
|
||||||
|
*/
|
||||||
|
export const createDecisionBoxPathD = (x: number, y: number, size: number): string => {
|
||||||
|
return [
|
||||||
|
`M${x + size / 2},${y}`,
|
||||||
|
`L${x + size},${y - size / 2}`,
|
||||||
|
`L${x + size / 2},${y - size}`,
|
||||||
|
`L${x},${y - size / 2}`,
|
||||||
|
'Z',
|
||||||
|
].join(' ');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const question = async (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
|
||||||
|
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node), true);
|
||||||
|
|
||||||
|
const w = bbox.width + node.padding;
|
||||||
|
const h = bbox.height + node.padding;
|
||||||
|
const s = w + h;
|
||||||
|
|
||||||
|
const points = [
|
||||||
|
{ x: s / 2, y: 0 },
|
||||||
|
{ x: s, y: -s / 2 },
|
||||||
|
{ x: s / 2, y: -s },
|
||||||
|
{ x: 0, y: -s / 2 },
|
||||||
|
];
|
||||||
|
|
||||||
|
let polygon: d3.Selection<SVGPolygonElement | SVGGElement, unknown, null, undefined>;
|
||||||
|
const { cssStyles, useRough } = node;
|
||||||
|
|
||||||
|
if (useRough) {
|
||||||
|
// @ts-ignore
|
||||||
|
const rc = rough.svg(shapeSvg);
|
||||||
|
const options = userNodeOverrides(node, {});
|
||||||
|
const pathData = createDecisionBoxPathD(0, 0, s);
|
||||||
|
const roughNode = rc.path(pathData, options);
|
||||||
|
|
||||||
|
polygon = shapeSvg
|
||||||
|
.insert(() => roughNode, ':first-child')
|
||||||
|
.attr('transform', `translate(${-s / 2}, ${s / 2})`);
|
||||||
|
|
||||||
|
if (cssStyles) {
|
||||||
|
polygon.attr('style', cssStyles);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
polygon = insertPolygonShape(shapeSvg, s, s, points);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cssStyles) {
|
||||||
|
polygon.attr('style', cssStyles);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateNodeBounds(node, polygon);
|
||||||
|
|
||||||
|
node.intersect = function (point) {
|
||||||
|
log.warn('Intersect called');
|
||||||
|
return intersect.polygon(node, points, point);
|
||||||
|
};
|
||||||
|
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
@ -0,0 +1,77 @@
|
|||||||
|
import { log } from '$root/logger.js';
|
||||||
|
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
|
||||||
|
import intersect from '../intersect/index.js';
|
||||||
|
import type { Node } from '$root/rendering-util/types.d.ts';
|
||||||
|
import { userNodeOverrides } from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
|
||||||
|
import rough from 'roughjs';
|
||||||
|
import { insertPolygonShape } from './insertPolygonShape.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an SVG path for a special polygon shape with a left-inverted arrow.
|
||||||
|
* @param {number} x - The x coordinate of the top-left corner.
|
||||||
|
* @param {number} y - The y coordinate of the top-left corner.
|
||||||
|
* @param {number} width - The width of the shape.
|
||||||
|
* @param {number} height - The height of the shape.
|
||||||
|
* @returns {string} The path data for the special polygon shape.
|
||||||
|
*/
|
||||||
|
export const createPolygonPathD = (x: number, y: number, width: number, height: number): string => {
|
||||||
|
return [
|
||||||
|
`M${x - height / 2},${y}`,
|
||||||
|
`L${x + width},${y}`,
|
||||||
|
`L${x + width},${y - height}`,
|
||||||
|
`L${x - height / 2},${y - height}`,
|
||||||
|
`L${x},${y - height / 2}`,
|
||||||
|
'Z',
|
||||||
|
].join(' ');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const rect_left_inv_arrow = async (
|
||||||
|
parent: SVGAElement,
|
||||||
|
node: Node
|
||||||
|
): Promise<SVGAElement> => {
|
||||||
|
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node), true);
|
||||||
|
|
||||||
|
const w = bbox.width + node.padding;
|
||||||
|
const h = bbox.height + node.padding;
|
||||||
|
const points = [
|
||||||
|
{ x: -h / 2, y: 0 },
|
||||||
|
{ x: w, y: 0 },
|
||||||
|
{ x: w, y: -h },
|
||||||
|
{ x: -h / 2, y: -h },
|
||||||
|
{ x: 0, y: -h / 2 },
|
||||||
|
];
|
||||||
|
|
||||||
|
let polygon;
|
||||||
|
const { cssStyles, useRough } = node;
|
||||||
|
|
||||||
|
if (useRough) {
|
||||||
|
// @ts-ignore
|
||||||
|
const rc = rough.svg(shapeSvg);
|
||||||
|
const options = userNodeOverrides(node, {});
|
||||||
|
const pathData = createPolygonPathD(0, 0, w, h);
|
||||||
|
const roughNode = rc.path(pathData, options);
|
||||||
|
|
||||||
|
polygon = shapeSvg
|
||||||
|
.insert(() => roughNode, ':first-child')
|
||||||
|
.attr('transform', `translate(${-w / 2}, ${h / 2})`);
|
||||||
|
if (cssStyles) {
|
||||||
|
polygon.attr('style', cssStyles);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
polygon = insertPolygonShape(shapeSvg, w, h, points);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cssStyles) {
|
||||||
|
polygon.attr('style', cssStyles);
|
||||||
|
}
|
||||||
|
node.width = w + h;
|
||||||
|
node.height = h;
|
||||||
|
|
||||||
|
updateNodeBounds(node, polygon);
|
||||||
|
|
||||||
|
node.intersect = function (point) {
|
||||||
|
return intersect.polygon(node, points, point);
|
||||||
|
};
|
||||||
|
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
@ -0,0 +1,13 @@
|
|||||||
|
import type { Node, RectOptions } from '$root/rendering-util/types.d.ts';
|
||||||
|
import { drawRect } from './drawRect.js';
|
||||||
|
|
||||||
|
export const roundedRect = async (parent: SVGAElement, node: Node) => {
|
||||||
|
const options = {
|
||||||
|
rx: 5,
|
||||||
|
ry: 5,
|
||||||
|
classes: '',
|
||||||
|
} as RectOptions;
|
||||||
|
|
||||||
|
console.log('roundedRect XDX');
|
||||||
|
return drawRect(parent, node, options);
|
||||||
|
};
|
@ -0,0 +1,11 @@
|
|||||||
|
import type { Node, RectOptions } from '$root/rendering-util/types.d.ts';
|
||||||
|
import { drawRect } from './drawRect.js';
|
||||||
|
|
||||||
|
export const squareRect = async (parent: SVGAElement, node: Node) => {
|
||||||
|
const options = {
|
||||||
|
rx: 0,
|
||||||
|
ry: 0,
|
||||||
|
classes: '',
|
||||||
|
} as RectOptions;
|
||||||
|
return drawRect(parent, node, options);
|
||||||
|
};
|
@ -0,0 +1,93 @@
|
|||||||
|
import { log } from '$root/logger.js';
|
||||||
|
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
|
||||||
|
import intersect from '../intersect/index.js';
|
||||||
|
import type { Node } from '$root/rendering-util/types.d.ts';
|
||||||
|
import { userNodeOverrides } from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
|
||||||
|
import rough from 'roughjs';
|
||||||
|
import { createRoundedRectPathD } from './roundedRectPath.js';
|
||||||
|
|
||||||
|
export const createStadiumPathD = (
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
totalWidth: number,
|
||||||
|
totalHeight: number
|
||||||
|
) => {
|
||||||
|
const radius = totalHeight / 2;
|
||||||
|
return [
|
||||||
|
'M',
|
||||||
|
x + radius,
|
||||||
|
y, // Move to the start of the top-left arc
|
||||||
|
'H',
|
||||||
|
x + totalWidth - radius, // Draw horizontal line to the start of the top-right arc
|
||||||
|
'A',
|
||||||
|
radius,
|
||||||
|
radius,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
x + totalWidth,
|
||||||
|
y + radius, // Draw top-right arc
|
||||||
|
'H',
|
||||||
|
x, // Draw horizontal line to the start of the bottom-right arc
|
||||||
|
'A',
|
||||||
|
radius,
|
||||||
|
radius,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
x + totalWidth - radius,
|
||||||
|
y + totalHeight, // Draw bottom-right arc
|
||||||
|
'H',
|
||||||
|
x + radius, // Draw horizontal line to the start of the bottom-left arc
|
||||||
|
'A',
|
||||||
|
radius,
|
||||||
|
radius,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
x,
|
||||||
|
y + radius, // Draw bottom-left arc
|
||||||
|
'Z', // Close the path
|
||||||
|
].join(' ');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const stadium = async (parent: SVGAElement, node: Node) => {
|
||||||
|
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node), true);
|
||||||
|
|
||||||
|
const h = bbox.height + node.padding;
|
||||||
|
const w = bbox.width + h / 4 + node.padding;
|
||||||
|
|
||||||
|
let rect;
|
||||||
|
const { cssStyles, useRough } = node;
|
||||||
|
if (useRough) {
|
||||||
|
// @ts-ignore
|
||||||
|
const rc = rough.svg(shapeSvg);
|
||||||
|
const options = userNodeOverrides(node, {});
|
||||||
|
|
||||||
|
const pathData = createRoundedRectPathD(-w / 2, -h / 2, w, h, h / 2);
|
||||||
|
const roughNode = rc.path(pathData, options);
|
||||||
|
|
||||||
|
rect = shapeSvg.insert(() => roughNode, ':first-child');
|
||||||
|
rect.attr('class', 'basic label-container').attr('style', cssStyles);
|
||||||
|
} else {
|
||||||
|
rect = shapeSvg.insert('rect', ':first-child');
|
||||||
|
|
||||||
|
rect
|
||||||
|
.attr('class', 'basic label-container')
|
||||||
|
.attr('style', cssStyles)
|
||||||
|
.attr('rx', h / 2)
|
||||||
|
.attr('ry', h / 2)
|
||||||
|
.attr('x', -w / 2)
|
||||||
|
.attr('y', -h / 2)
|
||||||
|
.attr('width', w)
|
||||||
|
.attr('height', h);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateNodeBounds(node, rect);
|
||||||
|
|
||||||
|
node.intersect = function (point) {
|
||||||
|
return intersect.rect(node, point);
|
||||||
|
};
|
||||||
|
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
@ -0,0 +1,11 @@
|
|||||||
|
import type { Node } from '$root/rendering-util/types.d.ts';
|
||||||
|
import { drawRect } from './drawRect.js';
|
||||||
|
|
||||||
|
export const state = async (parent: SVGAElement, node: Node) => {
|
||||||
|
const options = {
|
||||||
|
rx: 5,
|
||||||
|
ry: 5,
|
||||||
|
classes: 'flowchart-node',
|
||||||
|
};
|
||||||
|
return drawRect(parent, node, options);
|
||||||
|
};
|
@ -0,0 +1,87 @@
|
|||||||
|
import { log } from '$root/logger.js';
|
||||||
|
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
|
||||||
|
import intersect from '../intersect/index.js';
|
||||||
|
import type { Node } from '$root/rendering-util/types.d.ts';
|
||||||
|
import { userNodeOverrides } from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
|
||||||
|
import rough from 'roughjs';
|
||||||
|
import { insertPolygonShape } from './insertPolygonShape.js';
|
||||||
|
|
||||||
|
export const createSubroutinePathD = (
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
width: number,
|
||||||
|
height: number
|
||||||
|
): string => {
|
||||||
|
const offset = 8;
|
||||||
|
return [
|
||||||
|
`M${x - offset},${y}`,
|
||||||
|
`H${x + width + offset}`,
|
||||||
|
`V${y + height}`,
|
||||||
|
`H${x - offset}`,
|
||||||
|
`V${y}`,
|
||||||
|
'M',
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
'H',
|
||||||
|
x + width,
|
||||||
|
'V',
|
||||||
|
y + height,
|
||||||
|
'H',
|
||||||
|
x,
|
||||||
|
'Z',
|
||||||
|
].join(' ');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const subroutine = async (parent: SVGAElement, node: Node) => {
|
||||||
|
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node), true);
|
||||||
|
const halfPadding = (node?.padding || 0) / 2;
|
||||||
|
const w = bbox.width + node.padding;
|
||||||
|
const h = bbox.height + node.padding;
|
||||||
|
const x = -bbox.width / 2 - halfPadding;
|
||||||
|
const y = -bbox.height / 2 - halfPadding;
|
||||||
|
let rect;
|
||||||
|
const { cssStyles, useRough } = 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 },
|
||||||
|
];
|
||||||
|
|
||||||
|
if (useRough) {
|
||||||
|
// @ts-ignore
|
||||||
|
const rc = rough.svg(shapeSvg);
|
||||||
|
const options = userNodeOverrides(node, {});
|
||||||
|
const pathData = createSubroutinePathD(-w / 2, -h / 2, w, h);
|
||||||
|
|
||||||
|
const roughNode = rc.rectangle(x - 8, y, w + 16, h, options);
|
||||||
|
const l1 = rc.line(x, y, x, y + h, options);
|
||||||
|
const l2 = rc.line(x + w, y, x + w, y + h, options);
|
||||||
|
|
||||||
|
shapeSvg.insert(() => l1, ':first-child');
|
||||||
|
shapeSvg.insert(() => l2, ':first-child');
|
||||||
|
rect = shapeSvg.insert(() => roughNode, ':first-child');
|
||||||
|
|
||||||
|
rect.attr('class', 'basic label-container').attr('style', cssStyles);
|
||||||
|
} else {
|
||||||
|
const el = insertPolygonShape(shapeSvg, w, h, points);
|
||||||
|
if (cssStyles) {
|
||||||
|
el.attr('style', cssStyles);
|
||||||
|
}
|
||||||
|
updateNodeBounds(node, el);
|
||||||
|
}
|
||||||
|
|
||||||
|
node.intersect = function (point) {
|
||||||
|
return intersect.polygon(node, points, point);
|
||||||
|
};
|
||||||
|
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default subroutine;
|
@ -0,0 +1,80 @@
|
|||||||
|
import { log } from '$root/logger.js';
|
||||||
|
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
|
||||||
|
import intersect from '../intersect/index.js';
|
||||||
|
import type { Node } from '$root/rendering-util/types.d.ts';
|
||||||
|
import { userNodeOverrides } from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
|
||||||
|
import rough from 'roughjs';
|
||||||
|
import { insertPolygonShape } from './insertPolygonShape.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an SVG path for a trapezoid shape.
|
||||||
|
* @param {number} x - The x coordinate of the top-left corner.
|
||||||
|
* @param {number} y - The y coordinate of the top-left corner.
|
||||||
|
* @param {number} width - The width of the shape.
|
||||||
|
* @param {number} height - The height of the shape.
|
||||||
|
* @returns {string} The path data for the trapezoid shape.
|
||||||
|
*/
|
||||||
|
export const createTrapezoidPathD = (
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
width: number,
|
||||||
|
height: number
|
||||||
|
): string => {
|
||||||
|
return [
|
||||||
|
`M${x - (2 * height) / 6},${y}`,
|
||||||
|
`L${x + width + (2 * height) / 6},${y}`,
|
||||||
|
`L${x + width - height / 6},${y - height}`,
|
||||||
|
`L${x + height / 6},${y - height}`,
|
||||||
|
'Z',
|
||||||
|
].join(' ');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const trapezoid = async (parent: SVGAElement, node: Node): Promise<SVGAElement> => {
|
||||||
|
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node), true);
|
||||||
|
|
||||||
|
const w = bbox.width + node.padding;
|
||||||
|
const h = bbox.height + node.padding;
|
||||||
|
const points = [
|
||||||
|
{ x: (-2 * h) / 6, y: 0 },
|
||||||
|
{ x: w + (2 * h) / 6, y: 0 },
|
||||||
|
{ x: w - h / 6, y: -h },
|
||||||
|
{ x: h / 6, y: -h },
|
||||||
|
];
|
||||||
|
|
||||||
|
let polygon: d3.Selection<SVGPolygonElement | SVGGElement, unknown, null, undefined>;
|
||||||
|
const { cssStyles, useRough } = node;
|
||||||
|
|
||||||
|
if (useRough) {
|
||||||
|
console.log('Trapezoid: Inside use useRough');
|
||||||
|
// @ts-ignore
|
||||||
|
const rc = rough.svg(shapeSvg);
|
||||||
|
const options = userNodeOverrides(node, {});
|
||||||
|
const pathData = createTrapezoidPathD(0, 0, w, h);
|
||||||
|
const roughNode = rc.path(pathData, options);
|
||||||
|
|
||||||
|
polygon = shapeSvg
|
||||||
|
.insert(() => roughNode, ':first-child')
|
||||||
|
.attr('transform', `translate(${-w / 2}, ${h / 2})`);
|
||||||
|
|
||||||
|
if (cssStyles) {
|
||||||
|
polygon.attr('style', cssStyles);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
polygon = insertPolygonShape(shapeSvg, w, h, points);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cssStyles) {
|
||||||
|
polygon.attr('style', cssStyles);
|
||||||
|
}
|
||||||
|
|
||||||
|
node.width = w;
|
||||||
|
node.height = h;
|
||||||
|
|
||||||
|
updateNodeBounds(node, polygon);
|
||||||
|
|
||||||
|
node.intersect = function (point) {
|
||||||
|
return intersect.polygon(node, points, point);
|
||||||
|
};
|
||||||
|
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
@ -131,3 +131,6 @@ export function insertPolygonShape(parent, w, h, points) {
|
|||||||
.attr('class', 'label-container')
|
.attr('class', 'label-container')
|
||||||
.attr('transform', 'translate(' + -w / 2 + ',' + h / 2 + ')');
|
.attr('transform', 'translate(' + -w / 2 + ',' + h / 2 + ')');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getNodeClasses = (node, extra) =>
|
||||||
|
(node.useRough ? 'rough-node' : 'node') + ' ' + node.cssClasses + ' ' + (extra || '');
|
||||||
|
14
packages/mermaid/src/rendering-util/types.d.ts
vendored
14
packages/mermaid/src/rendering-util/types.d.ts
vendored
@ -1,5 +1,5 @@
|
|||||||
import type { MermaidConfig } from '$root/config.type.ts';
|
import config from '../../dist/defaultConfig';
|
||||||
|
import type { MermaidConfig } from '../../dist/config.type';
|
||||||
export type MarkdownWordType = 'normal' | 'strong' | 'emphasis';
|
export type MarkdownWordType = 'normal' | 'strong' | 'emphasis';
|
||||||
export interface MarkdownWord {
|
export interface MarkdownWord {
|
||||||
content: string;
|
content: string;
|
||||||
@ -57,6 +57,10 @@ interface Node {
|
|||||||
borderStyle?: string;
|
borderStyle?: string;
|
||||||
borderWidth?: number;
|
borderWidth?: number;
|
||||||
labelTextColor?: string;
|
labelTextColor?: string;
|
||||||
|
|
||||||
|
// Flowchart specific properties
|
||||||
|
x?: number;
|
||||||
|
y?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Common properties for any edge in the system
|
// Common properties for any edge in the system
|
||||||
@ -90,6 +94,12 @@ interface Edge {
|
|||||||
useRough?: boolean;
|
useRough?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface RectOptions {
|
||||||
|
rx: number;
|
||||||
|
ry: number;
|
||||||
|
classes: string;
|
||||||
|
}
|
||||||
|
|
||||||
// Extending the Node interface for specific types if needed
|
// Extending the Node interface for specific types if needed
|
||||||
interface ClassDiagramNode extends Node {
|
interface ClassDiagramNode extends Node {
|
||||||
memberData: any; // Specific property for class diagram nodes
|
memberData: any; // Specific property for class diagram nodes
|
||||||
|
Loading…
x
Reference in New Issue
Block a user