mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-10 19:09:44 +02:00
Compare commits
46 Commits
@mermaid-j
...
renovate/t
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d22cad07e3 | ||
![]() |
166782cd38 | ||
![]() |
b37eb6d0d1 | ||
![]() |
f759f5dcf7 | ||
![]() |
80bcefe321 | ||
![]() |
70cbbe69d8 | ||
![]() |
baf4093e8d | ||
![]() |
fd185f7694 | ||
![]() |
027d7b6368 | ||
![]() |
7986b66a88 | ||
![]() |
edb0edc451 | ||
![]() |
b511a2e9be | ||
![]() |
b80ea26a2b | ||
![]() |
f88986a87d | ||
![]() |
e16f0848ab | ||
![]() |
25fa26d915 | ||
![]() |
62915183b1 | ||
![]() |
6874ab3fb6 | ||
![]() |
040af4f545 | ||
![]() |
65ca3eabfd | ||
![]() |
8b9bbad842 | ||
![]() |
d2773db7dc | ||
![]() |
3840451fda | ||
![]() |
cfe9238882 | ||
![]() |
0dd46a3543 | ||
![]() |
f81e63663c | ||
![]() |
7109e3a17f | ||
![]() |
e0bd51941e | ||
![]() |
38f4e67ca7 | ||
![]() |
681d829227 | ||
![]() |
164e44c3d9 | ||
![]() |
2e1d156d66 | ||
![]() |
e863ad1547 | ||
![]() |
7091792694 | ||
![]() |
efd94b705d | ||
![]() |
9ec989e633 | ||
![]() |
a716a525c3 | ||
![]() |
11abfc9ae5 | ||
![]() |
227cef05b3 | ||
![]() |
81b0ffb92a | ||
![]() |
1d3681053b | ||
![]() |
93df13898f | ||
![]() |
8314554eb5 | ||
![]() |
b7c03dc27e | ||
![]() |
c7f2f609a9 | ||
![]() |
4c3de3a1ec |
5
.changeset/clean-wolves-turn.md
Normal file
5
.changeset/clean-wolves-turn.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'mermaid': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: Render newlines as spaces in class diagrams
|
5
.changeset/crazy-loops-matter.md
Normal file
5
.changeset/crazy-loops-matter.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'mermaid': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: Handle arrows correctly when auto number is enabled
|
5
.changeset/four-eyes-wish.md
Normal file
5
.changeset/four-eyes-wish.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'mermaid': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: Ensure edge label color is applied when using classDef with edge IDs
|
5
.changeset/hungry-baths-glow.md
Normal file
5
.changeset/hungry-baths-glow.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'mermaid': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
feat: Added support for new participant types (`actor`, `boundary`, `control`, `entity`, `database`, `collections`, `queue`) in `sequenceDiagram`.
|
7
.changeset/hungry-guests-drive.md
Normal file
7
.changeset/hungry-guests-drive.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
'mermaid': minor
|
||||||
|
'@mermaid-js/layout-tidy-tree': minor
|
||||||
|
'@mermaid-js/layout-elk': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
feat: Update mindmap rendering to support multiple layouts, improved edge intersections, and new shapes
|
9
.changeset/revert-marked-dependency.md
Normal file
9
.changeset/revert-marked-dependency.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
'mermaid': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
chore: revert marked dependency from ^15.0.7 to ^16.0.0
|
||||||
|
|
||||||
|
- Reverted marked package version to ^16.0.0 for better compatibility
|
||||||
|
- This is a dependency update that maintains API compatibility
|
||||||
|
- All tests pass with the updated version
|
@@ -8,6 +8,7 @@ compositTitleSize
|
|||||||
cose
|
cose
|
||||||
curv
|
curv
|
||||||
doublecircle
|
doublecircle
|
||||||
|
elem
|
||||||
elems
|
elems
|
||||||
gantt
|
gantt
|
||||||
gitgraph
|
gitgraph
|
||||||
|
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -89,7 +89,7 @@ jobs:
|
|||||||
continue-on-error: ${{ github.event_name == 'push' }}
|
continue-on-error: ${{ github.event_name == 'push' }}
|
||||||
run: pnpm run docs:verify
|
run: pnpm run docs:verify
|
||||||
|
|
||||||
- uses: testomatio/check-tests@0ea638fcec1820cf2e7b9854fdbdd04128a55bd4 # stable
|
- uses: testomatio/check-tests@92979a6bea51bfe6f95275e7484709ab7ea4d3f9 # stable
|
||||||
with:
|
with:
|
||||||
framework: cypress
|
framework: cypress
|
||||||
tests: './cypress/e2e/**/**.spec.js'
|
tests: './cypress/e2e/**/**.spec.js'
|
||||||
|
@@ -113,8 +113,7 @@ describe('Configuration', () => {
|
|||||||
cy.get('path')
|
cy.get('path')
|
||||||
.first()
|
.first()
|
||||||
.should('have.attr', 'marker-end')
|
.should('have.attr', 'marker-end')
|
||||||
.should('exist')
|
.and('include', 'url(http://localhost');
|
||||||
.and('include', 'url(http\\:\\/\\/localhost');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('should not taint the initial configuration when using multiple directives', () => {
|
it('should not taint the initial configuration when using multiple directives', () => {
|
||||||
|
@@ -109,7 +109,7 @@ describe('Flowchart ELK', () => {
|
|||||||
const style = svg.attr('style');
|
const style = svg.attr('style');
|
||||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||||
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
||||||
verifyNumber(maxWidthValue, 380);
|
verifyNumber(maxWidthValue, 380, 15);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('8-elk: should render a flowchart when useMaxWidth is false', () => {
|
it('8-elk: should render a flowchart when useMaxWidth is false', () => {
|
||||||
@@ -128,7 +128,7 @@ describe('Flowchart ELK', () => {
|
|||||||
const width = parseFloat(svg.attr('width'));
|
const width = parseFloat(svg.attr('width'));
|
||||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||||
// expect(height).to.be.within(446 * 0.95, 446 * 1.05);
|
// expect(height).to.be.within(446 * 0.95, 446 * 1.05);
|
||||||
verifyNumber(width, 380);
|
verifyNumber(width, 380, 15);
|
||||||
expect(svg).to.not.have.attr('style');
|
expect(svg).to.not.have.attr('style');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -1186,4 +1186,17 @@ end
|
|||||||
imgSnapshotTest(graph, { htmlLabels: false });
|
imgSnapshotTest(graph, { htmlLabels: false });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('V2 - 17: should apply class def colour to edge label', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
` graph LR
|
||||||
|
id1(Start) link@-- "Label" -->id2(Stop)
|
||||||
|
style id1 fill:#f9f,stroke:#333,stroke-width:4px
|
||||||
|
|
||||||
|
class id2 myClass
|
||||||
|
classDef myClass fill:#bbf,stroke:#f66,stroke-width:2px,color:white,stroke-dasharray: 5 5
|
||||||
|
class link myClass
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -32,26 +32,8 @@
|
|||||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||||
rel="stylesheet"
|
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=Recursive:wght@300..1000&display=swap"
|
|
||||||
rel="stylesheet"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.recursive-mermaid {
|
|
||||||
font-family: 'Recursive', sans-serif;
|
|
||||||
font-optical-sizing: auto;
|
|
||||||
font-weight: 500;
|
|
||||||
font-style: normal;
|
|
||||||
font-variation-settings:
|
|
||||||
'slnt' 0,
|
|
||||||
'CASL' 0,
|
|
||||||
'CRSV' 0.5,
|
|
||||||
'MONO' 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
/* background: rgb(221, 208, 208); */
|
/* background: rgb(221, 208, 208); */
|
||||||
/* background: #333; */
|
/* background: #333; */
|
||||||
@@ -63,9 +45,7 @@
|
|||||||
h1 {
|
h1 {
|
||||||
color: grey;
|
color: grey;
|
||||||
}
|
}
|
||||||
.mermaid {
|
|
||||||
border: 1px solid red;
|
|
||||||
}
|
|
||||||
.mermaid2 {
|
.mermaid2 {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@@ -103,11 +83,6 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.class2 {
|
|
||||||
fill: red;
|
|
||||||
fill-opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* tspan {
|
/* tspan {
|
||||||
font-size: 6px !important;
|
font-size: 6px !important;
|
||||||
} */
|
} */
|
||||||
@@ -130,76 +105,194 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<pre id="diagram4" class="mermaid2">
|
|
||||||
---
|
|
||||||
config:
|
|
||||||
layout: tidy-tree
|
|
||||||
---
|
|
||||||
mindmap
|
|
||||||
root((mindmap))
|
|
||||||
Origins
|
|
||||||
Long history
|
|
||||||
::icon(fa fa-book)
|
|
||||||
Popularisation
|
|
||||||
British popular psychology author Tony Buzan
|
|
||||||
Research
|
|
||||||
On effectiveness<br/>and features
|
|
||||||
On Automatic creation
|
|
||||||
Uses
|
|
||||||
Creative techniques
|
|
||||||
Strategic planning
|
|
||||||
Argument mapping
|
|
||||||
Tools
|
|
||||||
Pen and paper
|
|
||||||
Mermaid
|
|
||||||
|
|
||||||
</pre>
|
|
||||||
<pre id="diagram4" class="mermaid">
|
<pre id="diagram4" class="mermaid">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
layout: tidy-tree
|
layout: elk
|
||||||
---
|
---
|
||||||
mindmap
|
flowchart-elk TB
|
||||||
root((mindmap is a long thing))
|
c1-->a2
|
||||||
A
|
subgraph one
|
||||||
B
|
a1-->a2
|
||||||
C
|
end
|
||||||
D
|
subgraph two
|
||||||
</pre
|
b1-->b2
|
||||||
|
end
|
||||||
|
subgraph three
|
||||||
|
c1-->c2
|
||||||
|
end
|
||||||
|
one --> two
|
||||||
|
three --> two
|
||||||
|
two --> c2
|
||||||
|
|
||||||
|
</pre
|
||||||
>
|
>
|
||||||
<pre id="diagram4" class="mermaid">
|
<pre id="diagram4" class="mermaid">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
layout: tidy-tree
|
layout: elk
|
||||||
---
|
---
|
||||||
mindmap
|
flowchart TB
|
||||||
root((mindmap))
|
|
||||||
A
|
process_C
|
||||||
B
|
subgraph container_Alpha
|
||||||
</pre
|
subgraph process_B
|
||||||
|
pppB
|
||||||
|
end
|
||||||
|
subgraph process_A
|
||||||
|
pppA
|
||||||
|
end
|
||||||
|
process_B-->|via_AWSBatch|container_Beta
|
||||||
|
process_A-->|messages|container_Beta
|
||||||
|
end
|
||||||
|
|
||||||
|
</pre
|
||||||
>
|
>
|
||||||
<pre id="diagram4" class="mermaid">
|
<pre id="diagram4" class="mermaid">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
layout: tidy-tree
|
layout: elk
|
||||||
---
|
---
|
||||||
mindmap
|
flowchart TB
|
||||||
root((mindmap))
|
subgraph container_Beta
|
||||||
A
|
process_C
|
||||||
a
|
end
|
||||||
apa[I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on]
|
subgraph container_Alpha
|
||||||
apa2[I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on]
|
subgraph process_B
|
||||||
b
|
pppB
|
||||||
c
|
end
|
||||||
d
|
subgraph process_A
|
||||||
B
|
pppA
|
||||||
apa3[I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on]
|
end
|
||||||
D
|
process_B-->|via_AWSBatch|container_Beta
|
||||||
apa5[I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on]
|
process_A-->|messages|container_Beta
|
||||||
apa4[I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on]
|
end
|
||||||
|
|
||||||
</pre>
|
</pre
|
||||||
|
>
|
||||||
|
<pre id="diagram4" class="mermaid">
|
||||||
|
---
|
||||||
|
config:
|
||||||
|
layout: elk
|
||||||
|
---
|
||||||
|
flowchart TB
|
||||||
|
subgraph container_Beta
|
||||||
|
process_C
|
||||||
|
end
|
||||||
|
|
||||||
|
process_B-->|via_AWSBatch|container_Beta
|
||||||
|
|
||||||
|
|
||||||
|
</pre
|
||||||
|
>
|
||||||
|
<pre id="diagram4" class="mermaid">
|
||||||
|
---
|
||||||
|
config:
|
||||||
|
layout: elk
|
||||||
|
---
|
||||||
|
classDiagram
|
||||||
|
note "I love this diagram!\nDo you love it?"
|
||||||
|
Class01 <|-- AveryLongClass : Cool
|
||||||
|
<<interface>> Class01
|
||||||
|
Class03 "1" *-- "*" Class04
|
||||||
|
Class05 "1" o-- "many" Class06
|
||||||
|
Class07 "1" .. "*" Class08
|
||||||
|
Class09 "1" --> "*" C2 : Where am i?
|
||||||
|
Class09 "*" --* "*" C3
|
||||||
|
Class09 "1" --|> "1" Class07
|
||||||
|
Class12 <|.. Class08
|
||||||
|
Class11 ..>Class12
|
||||||
|
Class07 : equals()
|
||||||
|
Class07 : Object[] elementData
|
||||||
|
Class01 : size()
|
||||||
|
Class01 : int chimp
|
||||||
|
Class01 : int gorilla
|
||||||
|
Class01 : -int privateChimp
|
||||||
|
Class01 : +int publicGorilla
|
||||||
|
Class01 : #int protectedMarmoset
|
||||||
|
Class08 <--> C2: Cool label
|
||||||
|
class Class10 {
|
||||||
|
<<service>>
|
||||||
|
int id
|
||||||
|
test()
|
||||||
|
}
|
||||||
|
note for Class10 "Cool class\nI said it's very cool class!"
|
||||||
|
</pre
|
||||||
|
>
|
||||||
|
<pre id="diagram4" class="mermaid">
|
||||||
|
---
|
||||||
|
config:
|
||||||
|
layout: elk
|
||||||
|
---
|
||||||
|
requirementDiagram
|
||||||
|
requirement test_req {
|
||||||
|
id: 1
|
||||||
|
text: the test text.
|
||||||
|
risk: high
|
||||||
|
verifymethod: test
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity {
|
||||||
|
type: simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
test_entity - satisfies -> test_req
|
||||||
|
</pre
|
||||||
|
>
|
||||||
|
<pre id="diagram4" class="mermaid">
|
||||||
|
---
|
||||||
|
config:
|
||||||
|
layout: elk
|
||||||
|
---
|
||||||
|
flowchart-elk TB
|
||||||
|
internet
|
||||||
|
nat
|
||||||
|
router
|
||||||
|
compute1
|
||||||
|
|
||||||
|
subgraph project
|
||||||
|
router
|
||||||
|
nat
|
||||||
|
subgraph subnet1
|
||||||
|
compute1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
%% router --> subnet1
|
||||||
|
subnet1 --> nat
|
||||||
|
%% nat --> internet
|
||||||
|
</pre
|
||||||
|
>
|
||||||
|
<pre id="diagram4" class="mermaid">
|
||||||
|
---
|
||||||
|
config:
|
||||||
|
layout: elk
|
||||||
|
---
|
||||||
|
flowchart-elk TB
|
||||||
|
internet
|
||||||
|
nat
|
||||||
|
router
|
||||||
|
lb1
|
||||||
|
lb2
|
||||||
|
compute1
|
||||||
|
compute2
|
||||||
|
subgraph project
|
||||||
|
router
|
||||||
|
nat
|
||||||
|
subgraph subnet1
|
||||||
|
compute1
|
||||||
|
lb1
|
||||||
|
end
|
||||||
|
subgraph subnet2
|
||||||
|
compute2
|
||||||
|
lb2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
internet --> router
|
||||||
|
router --> subnet1 & subnet2
|
||||||
|
subnet1 & subnet2 --> nat --> internet
|
||||||
|
</pre
|
||||||
|
>
|
||||||
<pre id="diagram4" class="mermaid">
|
<pre id="diagram4" class="mermaid">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
@@ -227,221 +320,149 @@ treemap
|
|||||||
"Leaf 2.2": 25
|
"Leaf 2.2": 25
|
||||||
"Leaf 2.3": 12
|
"Leaf 2.3": 12
|
||||||
|
|
||||||
classDef class1 fill:red,color:blue,stroke:#FFD600;
|
</pre>
|
||||||
|
<pre id="diagram5" class="mermaid">
|
||||||
|
---
|
||||||
|
config:
|
||||||
|
layout: elk
|
||||||
|
flowchart:
|
||||||
|
curve: rounded
|
||||||
|
---
|
||||||
|
flowchart LR
|
||||||
|
I["fa:fa-code Text"] -- Mermaid js --> D["Use<br/>the<br/>editor!"]
|
||||||
|
I --> D & D
|
||||||
|
D@{ shape: question}
|
||||||
|
I@{ shape: question}
|
||||||
|
|
||||||
|
</pre>
|
||||||
</pre
|
|
||||||
>
|
|
||||||
<pre id="diagram4" class="mermaid2">
|
|
||||||
---
|
|
||||||
config:
|
|
||||||
treemap:
|
|
||||||
valueFormat: '$0,0'
|
|
||||||
---
|
|
||||||
treemap
|
|
||||||
"Budget"
|
|
||||||
"Operations"
|
|
||||||
"Salaries": 7000
|
|
||||||
"Equipment": 2000
|
|
||||||
"Supplies": 1000
|
|
||||||
"Marketing"
|
|
||||||
"Advertising": 4000
|
|
||||||
"Events": 1000
|
|
||||||
|
|
||||||
</pre
|
|
||||||
>
|
|
||||||
<pre id="diagram4" class="mermaid">
|
<pre id="diagram4" class="mermaid">
|
||||||
treemap
|
|
||||||
title Accessible Treemap Title
|
|
||||||
"Category A"
|
|
||||||
"Item A1": 10
|
|
||||||
"Item A2": 20
|
|
||||||
"Category B"
|
|
||||||
"Item B1": 15
|
|
||||||
"Item B2": 25
|
|
||||||
</pre>
|
|
||||||
<pre id="diagram4" class="mermaid2">
|
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
layout: tidy-tree
|
layout: tidy-tree
|
||||||
---
|
---
|
||||||
mindmap
|
mindmap
|
||||||
root((mindmap))
|
root((mindmap))
|
||||||
a
|
Origins
|
||||||
apa[I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on]
|
Long history
|
||||||
apa2[I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on]
|
::icon(fa fa-book)
|
||||||
b
|
Popularisation
|
||||||
apa3[I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on]
|
British popular psychology author Tony Buzan
|
||||||
apa4[I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on. I am a long long multline string passing several levels of text. Lorum ipsum and so on]
|
Research
|
||||||
|
On effectiveness<br/>and features
|
||||||
|
On Automatic creation
|
||||||
|
Uses
|
||||||
|
Creative techniques
|
||||||
|
Strategic planning
|
||||||
|
Argument mapping
|
||||||
|
Tools
|
||||||
|
Pen and paper
|
||||||
|
Mermaid
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
---
|
|
||||||
config:
|
|
||||||
layout: tidy-tree
|
|
||||||
---
|
|
||||||
flowchart TB
|
|
||||||
A --> n0["1"]
|
|
||||||
A --> n1["2"]
|
|
||||||
A --> n2["3"]
|
|
||||||
A --> n3["4"] --> Q & R & S & T
|
|
||||||
</pre>
|
|
||||||
<pre id="diagram4" class="mermaid2">
|
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
layout: elk
|
layout: elk
|
||||||
---
|
flowchart:
|
||||||
flowchart TB
|
curve: linear
|
||||||
A --> n0["1"]
|
|
||||||
A --> n1["2"]
|
|
||||||
A --> n2["3"]
|
|
||||||
A --> n3["4"] --> Q & R & S & T
|
|
||||||
</pre>
|
|
||||||
<pre id="diagram4" class="mermaid2">
|
|
||||||
---
|
|
||||||
config:
|
|
||||||
layout: dagre
|
|
||||||
---
|
|
||||||
mindmap
|
|
||||||
root((mindmap is a long thing))
|
|
||||||
Origins
|
|
||||||
Long history
|
|
||||||
::icon(fa fa-book)
|
|
||||||
Popularisation
|
|
||||||
British popular psychology author Tony Buzan
|
|
||||||
Research
|
|
||||||
On effectiveness<br/>and features
|
|
||||||
On Automatic creation
|
|
||||||
Uses
|
|
||||||
Creative techniques
|
|
||||||
Strategic planning
|
|
||||||
Argument mapping
|
|
||||||
Tools
|
|
||||||
Pen and paper
|
|
||||||
Mermaid
|
|
||||||
</pre>
|
|
||||||
<pre id="diagram4" class="mermaid2">
|
|
||||||
---
|
|
||||||
config:
|
|
||||||
layout: cose-bilkent
|
|
||||||
---
|
|
||||||
mindmap
|
|
||||||
root((mindmap))
|
|
||||||
Origins
|
|
||||||
Long history
|
|
||||||
::icon(fa fa-book)
|
|
||||||
Popularisation
|
|
||||||
British popular psychology author Tony Buzan
|
|
||||||
Research
|
|
||||||
On effectiveness<br/>and features
|
|
||||||
On Automatic creation
|
|
||||||
Uses
|
|
||||||
Creative techniques
|
|
||||||
Strategic planning
|
|
||||||
Argument mapping
|
|
||||||
Tools
|
|
||||||
Pen and paper
|
|
||||||
Mermaid
|
|
||||||
</pre>
|
|
||||||
<pre id="diagram4" class="mermaid2">
|
|
||||||
---
|
|
||||||
config:
|
|
||||||
layout: elk
|
|
||||||
---
|
|
||||||
mindmap
|
|
||||||
root((mindmap))
|
|
||||||
Origins
|
|
||||||
Long history
|
|
||||||
::icon(fa fa-book)
|
|
||||||
Popularisation
|
|
||||||
British popular psychology author Tony Buzan
|
|
||||||
Research
|
|
||||||
On effectiveness<br/>and features
|
|
||||||
On Automatic creation
|
|
||||||
Uses
|
|
||||||
Creative techniques
|
|
||||||
Strategic planning
|
|
||||||
Argument mapping
|
|
||||||
Tools
|
|
||||||
Pen and paper
|
|
||||||
Mermaid
|
|
||||||
</pre>
|
|
||||||
<pre id="diagram4" class="mermaid2">
|
|
||||||
---
|
|
||||||
config:
|
|
||||||
layout: cose-bilkent
|
|
||||||
---
|
---
|
||||||
flowchart LR
|
flowchart LR
|
||||||
root{mindmap} --- Origins --- Europe
|
A[A] --> B[B]
|
||||||
Origins --> Asia
|
A[A] --- B([C])
|
||||||
root --- Background --- Rich
|
A@{ shape: diamond}
|
||||||
Background --- Poor
|
%%B@{ shape: diamond}
|
||||||
subgraph apa
|
|
||||||
Background
|
</pre>
|
||||||
Poor
|
<pre id="diagram4" class="mermaid">
|
||||||
|
---
|
||||||
|
config:
|
||||||
|
layout: elk
|
||||||
|
flowchart:
|
||||||
|
curve: linear
|
||||||
|
---
|
||||||
|
flowchart LR
|
||||||
|
A[A] -- Mermaid js --> B[B]
|
||||||
|
A[A] -- Mermaid js --- B[B]
|
||||||
|
A@{ shape: diamond}
|
||||||
|
B@{ shape: diamond}
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
<pre id="diagram4" class="mermaid">
|
||||||
|
---
|
||||||
|
config:
|
||||||
|
layout: elk
|
||||||
|
flowchart:
|
||||||
|
curve: rounded
|
||||||
|
---
|
||||||
|
flowchart LR
|
||||||
|
D["Use the editor"] -- Mermaid js --> I["fa:fa-code Text"]
|
||||||
|
I --> D & D
|
||||||
|
D@{ shape: question}
|
||||||
|
I@{ shape: question}
|
||||||
|
</pre>
|
||||||
|
<pre id="diagram4" class="mermaid">
|
||||||
|
---
|
||||||
|
config:
|
||||||
|
layout: elk
|
||||||
|
flowchart:
|
||||||
|
curve: rounded
|
||||||
|
elk:
|
||||||
|
nodePlacementStrategy: NETWORK_SIMPLEX
|
||||||
|
---
|
||||||
|
flowchart LR
|
||||||
|
D["Use the editor"] -- Mermaid js --> I["fa:fa-code Text"]
|
||||||
|
D --> I & I
|
||||||
|
a["a"]
|
||||||
|
D@{ shape: trap-b}
|
||||||
|
I@{ shape: lean-l}
|
||||||
|
</pre>
|
||||||
|
<pre id="diagram4" class="mermaid">
|
||||||
|
---
|
||||||
|
config:
|
||||||
|
layout: elk
|
||||||
|
|
||||||
|
---
|
||||||
|
flowchart LR
|
||||||
|
%% subgraph s1["Untitled subgraph"]
|
||||||
|
C["Evaluate"]
|
||||||
|
%% end
|
||||||
|
|
||||||
|
B --> C
|
||||||
|
</pre>
|
||||||
|
<pre id="diagram4" class="mermaid">
|
||||||
|
---
|
||||||
|
config:
|
||||||
|
layout: elk
|
||||||
|
flowchart:
|
||||||
|
//curve: linear
|
||||||
|
---
|
||||||
|
flowchart LR
|
||||||
|
%% A ==> B
|
||||||
|
%% A2 --> B2
|
||||||
|
A{A} --> B((Bo boo)) & B & B & B
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
<pre id="diagram4" class="mermaid">
|
||||||
|
---
|
||||||
|
config:
|
||||||
|
layout: elk
|
||||||
|
theme: default
|
||||||
|
look: classic
|
||||||
|
---
|
||||||
|
flowchart LR
|
||||||
|
subgraph s1["APA"]
|
||||||
|
D{"Use the editor"}
|
||||||
end
|
end
|
||||||
|
subgraph S2["S2"]
|
||||||
|
s1
|
||||||
|
I>"fa:fa-code Text"]
|
||||||
|
E["E"]
|
||||||
|
end
|
||||||
|
D -- Mermaid js --> I
|
||||||
|
D --> I & E
|
||||||
|
E --> I
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
---
|
|
||||||
config:
|
|
||||||
layout: elk
|
|
||||||
---
|
|
||||||
flowchart LR
|
|
||||||
root{mindmap} --- Origins --- Europe
|
|
||||||
Origins --> Asia
|
|
||||||
root --- Background --- Rich
|
|
||||||
Background --- Poor
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</pre>
|
|
||||||
<pre id="diagram4" class="mermaid2">
|
|
||||||
flowchart
|
|
||||||
D(("for D"))
|
|
||||||
</pre>
|
|
||||||
<pre id="diagram4" class="mermaid2">
|
|
||||||
flowchart LR
|
|
||||||
A e1@==> B
|
|
||||||
e1@{ animate: true}
|
|
||||||
</pre>
|
|
||||||
<pre id="diagram4" class="mermaid2">
|
|
||||||
flowchart LR
|
|
||||||
A e1@--> B
|
|
||||||
classDef animate stroke-width:2,stroke-dasharray:10\,8,stroke-dashoffset:-180,animation: edge-animation-frame 6s linear infinite, stroke-linecap: round
|
|
||||||
class e1 animate
|
|
||||||
</pre>
|
|
||||||
<h2>infinite</h2>
|
|
||||||
<pre id="diagram4" class="mermaid2">
|
|
||||||
flowchart LR
|
|
||||||
A e1@--> B
|
|
||||||
classDef animate stroke-dasharray: 9\,5,stroke-dashoffset: 900,animation: dash 25s linear infinite;
|
|
||||||
class e1 animate
|
|
||||||
</pre>
|
|
||||||
<h2>Mermaid - edge-animation-slow</h2>
|
|
||||||
<pre id="diagram4" class="mermaid2">
|
|
||||||
flowchart LR
|
|
||||||
A e1@--> B
|
|
||||||
e1@{ animation: fast}
|
|
||||||
</pre>
|
|
||||||
<h2>Mermaid - edge-animation-fast</h2>
|
|
||||||
<pre id="diagram4" class="mermaid2">
|
|
||||||
flowchart LR
|
|
||||||
A e1@--> B
|
|
||||||
classDef animate stroke-dasharray: 1000,stroke-dashoffset: 1000,animation: dash 10s linear;
|
|
||||||
class e1 edge-animation-fast
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<pre id="diagram4" class="mermaid2">
|
|
||||||
|
|
||||||
info </pre
|
|
||||||
>
|
|
||||||
<pre id="diagram4" class="mermaid2">
|
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
layout: elk
|
layout: elk
|
||||||
@@ -466,7 +487,7 @@ config:
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
layout: elk
|
layout: elk
|
||||||
@@ -479,45 +500,7 @@ config:
|
|||||||
D-->I
|
D-->I
|
||||||
D-->I
|
D-->I
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
---
|
|
||||||
config:
|
|
||||||
layout: elk
|
|
||||||
---
|
|
||||||
flowchart LR
|
|
||||||
a
|
|
||||||
subgraph s0["APA"]
|
|
||||||
subgraph s8["APA"]
|
|
||||||
subgraph s1["APA"]
|
|
||||||
D{"X"}
|
|
||||||
E[Q]
|
|
||||||
end
|
|
||||||
subgraph s3["BAPA"]
|
|
||||||
F[Q]
|
|
||||||
I
|
|
||||||
end
|
|
||||||
D --> I
|
|
||||||
D --> I
|
|
||||||
D --> I
|
|
||||||
|
|
||||||
I{"X"}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
</pre>
|
|
||||||
<pre id="diagram4" class="mermaid2">
|
|
||||||
---
|
|
||||||
config:
|
|
||||||
layout: elk
|
|
||||||
---
|
|
||||||
flowchart LR
|
|
||||||
a
|
|
||||||
D{"Use the editor"}
|
|
||||||
|
|
||||||
D -- Mermaid js --> I{"fa:fa-code Text"}
|
|
||||||
D-->I
|
|
||||||
D-->I
|
|
||||||
</pre>
|
|
||||||
<pre id="diagram4" class="mermaid2">
|
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
layout: elk
|
layout: elk
|
||||||
@@ -556,7 +539,7 @@ flowchart LR
|
|||||||
n8@{ shape: rect}
|
n8@{ shape: rect}
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
layout: elk
|
layout: elk
|
||||||
@@ -572,7 +555,7 @@ flowchart LR
|
|||||||
|
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
layout: elk
|
layout: elk
|
||||||
@@ -581,7 +564,7 @@ flowchart LR
|
|||||||
A{A} --> B & C
|
A{A} --> B & C
|
||||||
</pre
|
</pre
|
||||||
>
|
>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
layout: elk
|
layout: elk
|
||||||
@@ -593,7 +576,7 @@ flowchart LR
|
|||||||
end
|
end
|
||||||
</pre
|
</pre
|
||||||
>
|
>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
layout: elk
|
layout: elk
|
||||||
@@ -611,7 +594,7 @@ flowchart LR
|
|||||||
|
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
kanban:
|
kanban:
|
||||||
@@ -630,81 +613,81 @@ kanban
|
|||||||
task3[💻 Develop login feature]@{ ticket: 103 }
|
task3[💻 Develop login feature]@{ ticket: 103 }
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Default] --> A@{ icon: 'fa:bell', form: 'rounded' }
|
nA[Default] --> A@{ icon: 'fa:bell', form: 'rounded' }
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Style] --> A@{ icon: 'fa:bell', form: 'rounded' }
|
nA[Style] --> A@{ icon: 'fa:bell', form: 'rounded' }
|
||||||
style A fill:#f9f,stroke:#333,stroke-width:4px
|
style A fill:#f9f,stroke:#333,stroke-width:4px
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Class] --> A@{ icon: 'fa:bell', form: 'rounded' }
|
nA[Class] --> A@{ icon: 'fa:bell', form: 'rounded' }
|
||||||
A:::AClass
|
A:::AClass
|
||||||
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Class] --> A@{ icon: 'logos:aws', form: 'rounded' }
|
nA[Class] --> A@{ icon: 'logos:aws', form: 'rounded' }
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Default] --> A@{ icon: 'fa:bell', form: 'square' }
|
nA[Default] --> A@{ icon: 'fa:bell', form: 'square' }
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Style] --> A@{ icon: 'fa:bell', form: 'square' }
|
nA[Style] --> A@{ icon: 'fa:bell', form: 'square' }
|
||||||
style A fill:#f9f,stroke:#333,stroke-width:4px
|
style A fill:#f9f,stroke:#333,stroke-width:4px
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Class] --> A@{ icon: 'fa:bell', form: 'square' }
|
nA[Class] --> A@{ icon: 'fa:bell', form: 'square' }
|
||||||
A:::AClass
|
A:::AClass
|
||||||
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Class] --> A@{ icon: 'logos:aws', form: 'square' }
|
nA[Class] --> A@{ icon: 'logos:aws', form: 'square' }
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Default] --> A@{ icon: 'fa:bell', form: 'circle' }
|
nA[Default] --> A@{ icon: 'fa:bell', form: 'circle' }
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Style] --> A@{ icon: 'fa:bell', form: 'circle' }
|
nA[Style] --> A@{ icon: 'fa:bell', form: 'circle' }
|
||||||
style A fill:#f9f,stroke:#333,stroke-width:4px
|
style A fill:#f9f,stroke:#333,stroke-width:4px
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Class] --> A@{ icon: 'fa:bell', form: 'circle' }
|
nA[Class] --> A@{ icon: 'fa:bell', form: 'circle' }
|
||||||
A:::AClass
|
A:::AClass
|
||||||
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Class] --> A@{ icon: 'logos:aws', form: 'circle' }
|
nA[Class] --> A@{ icon: 'logos:aws', form: 'circle' }
|
||||||
A:::AClass
|
A:::AClass
|
||||||
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
nA[Style] --> A@{ icon: 'logos:aws', form: 'circle' }
|
nA[Style] --> A@{ icon: 'logos:aws', form: 'circle' }
|
||||||
style A fill:#f9f,stroke:#333,stroke-width:4px
|
style A fill:#f9f,stroke:#333,stroke-width:4px
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
kanban
|
kanban
|
||||||
id2[In progress]
|
id2[In progress]
|
||||||
docs[Create Blog about the new diagram]@{ priority: 'Very Low', ticket: MC-2037, assigned: 'knsv' }
|
docs[Create Blog about the new diagram]@{ priority: 'Very Low', ticket: MC-2037, assigned: 'knsv' }
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid2">
|
<pre id="diagram4" class="mermaid">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
kanban:
|
kanban:
|
||||||
@@ -768,18 +751,22 @@ kanban
|
|||||||
alert('It worked');
|
alert('It worked');
|
||||||
}
|
}
|
||||||
await mermaid.initialize({
|
await mermaid.initialize({
|
||||||
// theme: 'forest',
|
// theme: 'base',
|
||||||
// theme: 'default',
|
// theme: 'default',
|
||||||
// theme: 'forest',
|
// theme: 'forest',
|
||||||
// handDrawnSeed: 12,
|
// handDrawnSeed: 12,
|
||||||
// look: 'handDrawn',
|
// look: 'handDrawn',
|
||||||
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
|
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
|
||||||
// layout: 'dagre',
|
// layout: 'dagre',
|
||||||
// layout: 'elk',
|
layout: 'elk',
|
||||||
// layout: 'fixed',
|
// layout: 'fixed',
|
||||||
// htmlLabels: false,
|
// htmlLabels: false,
|
||||||
flowchart: { titleTopMargin: 10 },
|
flowchart: { titleTopMargin: 10 },
|
||||||
fontFamily: "'Recursive', sans-serif",
|
|
||||||
|
// fontFamily: 'Caveat',
|
||||||
|
// fontFamily: 'Kalam',
|
||||||
|
// fontFamily: 'courier',
|
||||||
|
fontFamily: 'arial',
|
||||||
sequence: {
|
sequence: {
|
||||||
actorFontFamily: 'courier',
|
actorFontFamily: 'courier',
|
||||||
noteFontFamily: 'courier',
|
noteFontFamily: 'courier',
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
# Interface: ExternalDiagramDefinition
|
# Interface: ExternalDiagramDefinition
|
||||||
|
|
||||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:94](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L94)
|
Defined in: [packages/mermaid/src/diagram-api/types.ts:96](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L96)
|
||||||
|
|
||||||
## Properties
|
## Properties
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ Defined in: [packages/mermaid/src/diagram-api/types.ts:94](https://github.com/me
|
|||||||
|
|
||||||
> **detector**: `DiagramDetector`
|
> **detector**: `DiagramDetector`
|
||||||
|
|
||||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:96](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L96)
|
Defined in: [packages/mermaid/src/diagram-api/types.ts:98](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L98)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ Defined in: [packages/mermaid/src/diagram-api/types.ts:96](https://github.com/me
|
|||||||
|
|
||||||
> **id**: `string`
|
> **id**: `string`
|
||||||
|
|
||||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:95](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L95)
|
Defined in: [packages/mermaid/src/diagram-api/types.ts:97](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L97)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -34,4 +34,4 @@ Defined in: [packages/mermaid/src/diagram-api/types.ts:95](https://github.com/me
|
|||||||
|
|
||||||
> **loader**: `DiagramLoader`
|
> **loader**: `DiagramLoader`
|
||||||
|
|
||||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:97](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L97)
|
Defined in: [packages/mermaid/src/diagram-api/types.ts:99](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L99)
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
# Interface: LayoutLoaderDefinition
|
# Interface: LayoutLoaderDefinition
|
||||||
|
|
||||||
Defined in: [packages/mermaid/src/rendering-util/render.ts:21](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L21)
|
Defined in: [packages/mermaid/src/rendering-util/render.ts:24](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L24)
|
||||||
|
|
||||||
## Properties
|
## Properties
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ Defined in: [packages/mermaid/src/rendering-util/render.ts:21](https://github.co
|
|||||||
|
|
||||||
> `optional` **algorithm**: `string`
|
> `optional` **algorithm**: `string`
|
||||||
|
|
||||||
Defined in: [packages/mermaid/src/rendering-util/render.ts:24](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L24)
|
Defined in: [packages/mermaid/src/rendering-util/render.ts:27](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L27)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ Defined in: [packages/mermaid/src/rendering-util/render.ts:24](https://github.co
|
|||||||
|
|
||||||
> **loader**: `LayoutLoader`
|
> **loader**: `LayoutLoader`
|
||||||
|
|
||||||
Defined in: [packages/mermaid/src/rendering-util/render.ts:23](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L23)
|
Defined in: [packages/mermaid/src/rendering-util/render.ts:26](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L26)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -34,4 +34,4 @@ Defined in: [packages/mermaid/src/rendering-util/render.ts:23](https://github.co
|
|||||||
|
|
||||||
> **name**: `string`
|
> **name**: `string`
|
||||||
|
|
||||||
Defined in: [packages/mermaid/src/rendering-util/render.ts:22](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L22)
|
Defined in: [packages/mermaid/src/rendering-util/render.ts:25](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L25)
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
# Interface: RenderOptions
|
# Interface: RenderOptions
|
||||||
|
|
||||||
Defined in: [packages/mermaid/src/rendering-util/render.ts:7](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L7)
|
Defined in: [packages/mermaid/src/rendering-util/render.ts:10](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L10)
|
||||||
|
|
||||||
## Properties
|
## Properties
|
||||||
|
|
||||||
@@ -18,4 +18,4 @@ Defined in: [packages/mermaid/src/rendering-util/render.ts:7](https://github.com
|
|||||||
|
|
||||||
> `optional` **algorithm**: `string`
|
> `optional` **algorithm**: `string`
|
||||||
|
|
||||||
Defined in: [packages/mermaid/src/rendering-util/render.ts:8](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L8)
|
Defined in: [packages/mermaid/src/rendering-util/render.ts:11](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/render.ts#L11)
|
||||||
|
@@ -12,4 +12,4 @@
|
|||||||
|
|
||||||
> **SVG** = `d3.Selection`<`SVGSVGElement`, `unknown`, `Element` | `null`, `unknown`>
|
> **SVG** = `d3.Selection`<`SVGSVGElement`, `unknown`, `Element` | `null`, `unknown`>
|
||||||
|
|
||||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:126](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L126)
|
Defined in: [packages/mermaid/src/diagram-api/types.ts:128](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L128)
|
||||||
|
@@ -12,4 +12,4 @@
|
|||||||
|
|
||||||
> **SVGGroup** = `d3.Selection`<`SVGGElement`, `unknown`, `Element` | `null`, `unknown`>
|
> **SVGGroup** = `d3.Selection`<`SVGGElement`, `unknown`, `Element` | `null`, `unknown`>
|
||||||
|
|
||||||
Defined in: [packages/mermaid/src/diagram-api/types.ts:128](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L128)
|
Defined in: [packages/mermaid/src/diagram-api/types.ts:130](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/diagram-api/types.ts#L130)
|
||||||
|
@@ -1,16 +1,5 @@
|
|||||||
# @mermaid-js/layout-elk
|
# @mermaid-js/layout-elk
|
||||||
|
|
||||||
## 0.2.0
|
|
||||||
|
|
||||||
### Minor Changes
|
|
||||||
|
|
||||||
- [#6802](https://github.com/mermaid-js/mermaid/pull/6802) [`c8e5027`](https://github.com/mermaid-js/mermaid/commit/c8e50276e877c4de7593a09ec458c99353e65af8) Thanks [@darshanr0107](https://github.com/darshanr0107)! - feat: Update mindmap rendering to support multiple layouts, improved edge intersections, and new shapes
|
|
||||||
|
|
||||||
### Patch Changes
|
|
||||||
|
|
||||||
- Updated dependencies [[`33bc4a0`](https://github.com/mermaid-js/mermaid/commit/33bc4a0b4e2ca6d937bb0a8c4e2081b1362b2800), [`e0b45c2`](https://github.com/mermaid-js/mermaid/commit/e0b45c2d2b41c2a9038bf87646fa3ccd7560eb20), [`012530e`](https://github.com/mermaid-js/mermaid/commit/012530e98e9b8b80962ab270b6bb3b6d9f6ada05), [`c8e5027`](https://github.com/mermaid-js/mermaid/commit/c8e50276e877c4de7593a09ec458c99353e65af8)]:
|
|
||||||
- mermaid@11.11.0
|
|
||||||
|
|
||||||
## 0.1.9
|
## 0.1.9
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@mermaid-js/layout-elk",
|
"name": "@mermaid-js/layout-elk",
|
||||||
"version": "0.2.0",
|
"version": "0.1.9",
|
||||||
"description": "ELK layout engine for mermaid",
|
"description": "ELK layout engine for mermaid",
|
||||||
"module": "dist/mermaid-layout-elk.core.mjs",
|
"module": "dist/mermaid-layout-elk.core.mjs",
|
||||||
"types": "dist/layouts.d.ts",
|
"types": "dist/layouts.d.ts",
|
||||||
|
67
packages/mermaid-layout-elk/src/__tests__/geometry.spec.ts
Normal file
67
packages/mermaid-layout-elk/src/__tests__/geometry.spec.ts
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
import {
|
||||||
|
intersection,
|
||||||
|
ensureTrulyOutside,
|
||||||
|
makeInsidePoint,
|
||||||
|
tryNodeIntersect,
|
||||||
|
replaceEndpoint,
|
||||||
|
type RectLike,
|
||||||
|
type P,
|
||||||
|
} from '../geometry.js';
|
||||||
|
|
||||||
|
const approx = (a: number, b: number, eps = 1e-6) => Math.abs(a - b) < eps;
|
||||||
|
|
||||||
|
describe('geometry helpers', () => {
|
||||||
|
it('intersection: vertical approach hits bottom border', () => {
|
||||||
|
const rect: RectLike = { x: 0, y: 0, width: 100, height: 50 };
|
||||||
|
const h = rect.height / 2; // 25
|
||||||
|
const outside: P = { x: 0, y: 100 };
|
||||||
|
const inside: P = { x: 0, y: 0 };
|
||||||
|
const res = intersection(rect, outside, inside);
|
||||||
|
expect(approx(res.x, 0)).toBe(true);
|
||||||
|
expect(approx(res.y, h)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ensureTrulyOutside nudges near-boundary point outward', () => {
|
||||||
|
const rect: RectLike = { x: 0, y: 0, width: 100, height: 50 };
|
||||||
|
// near bottom boundary (y ~ h)
|
||||||
|
const near: P = { x: 0, y: rect.height / 2 - 0.2 };
|
||||||
|
const out = ensureTrulyOutside(rect, near, 10);
|
||||||
|
expect(out.y).toBeGreaterThan(rect.height / 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('makeInsidePoint keeps x for vertical and y from center', () => {
|
||||||
|
const rect: RectLike = { x: 10, y: 5, width: 100, height: 50 };
|
||||||
|
const outside: P = { x: 10, y: 40 };
|
||||||
|
const center: P = { x: 99, y: -123 }; // center y should be used
|
||||||
|
const inside = makeInsidePoint(rect, outside, center);
|
||||||
|
expect(inside.x).toBe(outside.x);
|
||||||
|
expect(inside.y).toBe(center.y);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('tryNodeIntersect returns null for wrong-side intersections', () => {
|
||||||
|
const rect: RectLike = { x: 0, y: 0, width: 100, height: 50 };
|
||||||
|
const outside: P = { x: -50, y: 0 };
|
||||||
|
const node = { intersect: () => ({ x: 10, y: 0 }) } as any; // right side of center
|
||||||
|
const res = tryNodeIntersect(node, rect, outside);
|
||||||
|
expect(res).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('replaceEndpoint dedup removes end/start appropriately', () => {
|
||||||
|
const pts: P[] = [
|
||||||
|
{ x: 0, y: 0 },
|
||||||
|
{ x: 1, y: 1 },
|
||||||
|
];
|
||||||
|
// remove duplicate end
|
||||||
|
replaceEndpoint(pts, 'end', { x: 1, y: 1 });
|
||||||
|
expect(pts.length).toBe(1);
|
||||||
|
|
||||||
|
const pts2: P[] = [
|
||||||
|
{ x: 0, y: 0 },
|
||||||
|
{ x: 1, y: 1 },
|
||||||
|
];
|
||||||
|
// remove duplicate start
|
||||||
|
replaceEndpoint(pts2, 'start', { x: 0, y: 0 });
|
||||||
|
expect(pts2.length).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
209
packages/mermaid-layout-elk/src/geometry.ts
Normal file
209
packages/mermaid-layout-elk/src/geometry.ts
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
/* Geometry utilities extracted from render.ts for reuse and testing */
|
||||||
|
|
||||||
|
export interface P {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RectLike {
|
||||||
|
x: number; // center x
|
||||||
|
y: number; // center y
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
padding?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NodeLike {
|
||||||
|
intersect?: (p: P) => P | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const EPS = 1;
|
||||||
|
export const PUSH_OUT = 10;
|
||||||
|
|
||||||
|
export const onBorder = (bounds: RectLike, p: P, tol = 0.5): boolean => {
|
||||||
|
const halfW = bounds.width / 2;
|
||||||
|
const halfH = bounds.height / 2;
|
||||||
|
const left = bounds.x - halfW;
|
||||||
|
const right = bounds.x + halfW;
|
||||||
|
const top = bounds.y - halfH;
|
||||||
|
const bottom = bounds.y + halfH;
|
||||||
|
|
||||||
|
const onLeft = Math.abs(p.x - left) <= tol && p.y >= top - tol && p.y <= bottom + tol;
|
||||||
|
const onRight = Math.abs(p.x - right) <= tol && p.y >= top - tol && p.y <= bottom + tol;
|
||||||
|
const onTop = Math.abs(p.y - top) <= tol && p.x >= left - tol && p.x <= right + tol;
|
||||||
|
const onBottom = Math.abs(p.y - bottom) <= tol && p.x >= left - tol && p.x <= right + tol;
|
||||||
|
return onLeft || onRight || onTop || onBottom;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute intersection between a rectangle (center x/y, width/height) and the line
|
||||||
|
* segment from insidePoint -\> outsidePoint. Returns the point on the rectangle border.
|
||||||
|
*
|
||||||
|
* This version avoids snapping to outsidePoint when certain variables evaluate to 0
|
||||||
|
* (previously caused vertical top/bottom cases to miss the border). It only enforces
|
||||||
|
* axis-constant behavior for purely vertical/horizontal approaches.
|
||||||
|
*/
|
||||||
|
export const intersection = (node: RectLike, outsidePoint: P, insidePoint: P): P => {
|
||||||
|
const x = node.x;
|
||||||
|
const y = node.y;
|
||||||
|
|
||||||
|
const dx = Math.abs(x - insidePoint.x);
|
||||||
|
const w = node.width / 2;
|
||||||
|
let r = insidePoint.x < outsidePoint.x ? w - dx : w + dx;
|
||||||
|
const h = node.height / 2;
|
||||||
|
|
||||||
|
const Q = Math.abs(outsidePoint.y - insidePoint.y);
|
||||||
|
const R = Math.abs(outsidePoint.x - insidePoint.x);
|
||||||
|
|
||||||
|
if (Math.abs(y - outsidePoint.y) * w > Math.abs(x - outsidePoint.x) * h) {
|
||||||
|
// Intersection is top or bottom of rect.
|
||||||
|
const q = insidePoint.y < outsidePoint.y ? outsidePoint.y - h - y : y - h - outsidePoint.y;
|
||||||
|
r = (R * q) / Q;
|
||||||
|
const res = {
|
||||||
|
x: insidePoint.x < outsidePoint.x ? insidePoint.x + r : insidePoint.x - R + r,
|
||||||
|
y: insidePoint.y < outsidePoint.y ? insidePoint.y + Q - q : insidePoint.y - Q + q,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Keep axis-constant special-cases only
|
||||||
|
if (R === 0) {
|
||||||
|
res.x = outsidePoint.x;
|
||||||
|
}
|
||||||
|
if (Q === 0) {
|
||||||
|
res.y = outsidePoint.y;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
// Intersection on sides of rect
|
||||||
|
if (insidePoint.x < outsidePoint.x) {
|
||||||
|
r = outsidePoint.x - w - x;
|
||||||
|
} else {
|
||||||
|
r = x - w - outsidePoint.x;
|
||||||
|
}
|
||||||
|
const q = (Q * r) / R;
|
||||||
|
let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : insidePoint.x - R + r;
|
||||||
|
let _y = insidePoint.y < outsidePoint.y ? insidePoint.y + q : insidePoint.y - q;
|
||||||
|
|
||||||
|
// Only handle axis-constant cases
|
||||||
|
if (R === 0) {
|
||||||
|
_x = outsidePoint.x;
|
||||||
|
}
|
||||||
|
if (Q === 0) {
|
||||||
|
_y = outsidePoint.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { x: _x, y: _y };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const outsideNode = (node: RectLike, point: P): boolean => {
|
||||||
|
const x = node.x;
|
||||||
|
const y = node.y;
|
||||||
|
const dx = Math.abs(point.x - x);
|
||||||
|
const dy = Math.abs(point.y - y);
|
||||||
|
const w = node.width / 2;
|
||||||
|
const h = node.height / 2;
|
||||||
|
return dx >= w || dy >= h;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ensureTrulyOutside = (bounds: RectLike, p: P, push = PUSH_OUT): P => {
|
||||||
|
const dx = Math.abs(p.x - bounds.x);
|
||||||
|
const dy = Math.abs(p.y - bounds.y);
|
||||||
|
const w = bounds.width / 2;
|
||||||
|
const h = bounds.height / 2;
|
||||||
|
if (Math.abs(dx - w) < EPS || Math.abs(dy - h) < EPS) {
|
||||||
|
const dirX = p.x - bounds.x;
|
||||||
|
const dirY = p.y - bounds.y;
|
||||||
|
const len = Math.sqrt(dirX * dirX + dirY * dirY);
|
||||||
|
if (len > 0) {
|
||||||
|
return {
|
||||||
|
x: bounds.x + (dirX / len) * (len + push),
|
||||||
|
y: bounds.y + (dirY / len) * (len + push),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const makeInsidePoint = (bounds: RectLike, outside: P, center: P): P => {
|
||||||
|
const isVertical = Math.abs(outside.x - bounds.x) < EPS;
|
||||||
|
const isHorizontal = Math.abs(outside.y - bounds.y) < EPS;
|
||||||
|
return {
|
||||||
|
x: isVertical
|
||||||
|
? outside.x
|
||||||
|
: outside.x < bounds.x
|
||||||
|
? bounds.x - bounds.width / 4
|
||||||
|
: bounds.x + bounds.width / 4,
|
||||||
|
y: isHorizontal ? outside.y : center.y,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const tryNodeIntersect = (node: NodeLike, bounds: RectLike, outside: P): P | null => {
|
||||||
|
if (!node?.intersect) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const res = node.intersect(outside);
|
||||||
|
if (!res) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const wrongSide =
|
||||||
|
(outside.x < bounds.x && res.x > bounds.x) || (outside.x > bounds.x && res.x < bounds.x);
|
||||||
|
if (wrongSide) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const dist = Math.hypot(outside.x - res.x, outside.y - res.y);
|
||||||
|
if (dist <= EPS) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const fallbackIntersection = (bounds: RectLike, outside: P, center: P): P => {
|
||||||
|
const inside = makeInsidePoint(bounds, outside, center);
|
||||||
|
return intersection(bounds, outside, inside);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const computeNodeIntersection = (
|
||||||
|
node: NodeLike,
|
||||||
|
bounds: RectLike,
|
||||||
|
outside: P,
|
||||||
|
center: P
|
||||||
|
): P => {
|
||||||
|
const outside2 = ensureTrulyOutside(bounds, outside);
|
||||||
|
return tryNodeIntersect(node, bounds, outside2) ?? fallbackIntersection(bounds, outside2, center);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const replaceEndpoint = (
|
||||||
|
points: P[],
|
||||||
|
which: 'start' | 'end',
|
||||||
|
value: P | null | undefined,
|
||||||
|
tol = 0.1
|
||||||
|
) => {
|
||||||
|
if (!value || points.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (which === 'start') {
|
||||||
|
if (
|
||||||
|
points.length > 0 &&
|
||||||
|
Math.abs(points[0].x - value.x) < tol &&
|
||||||
|
Math.abs(points[0].y - value.y) < tol
|
||||||
|
) {
|
||||||
|
// duplicate start remove it
|
||||||
|
points.shift();
|
||||||
|
} else {
|
||||||
|
points[0] = value;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const last = points.length - 1;
|
||||||
|
if (
|
||||||
|
points.length > 0 &&
|
||||||
|
Math.abs(points[last].x - value.x) < tol &&
|
||||||
|
Math.abs(points[last].y - value.y) < tol
|
||||||
|
) {
|
||||||
|
// duplicate end remove it
|
||||||
|
points.pop();
|
||||||
|
} else {
|
||||||
|
points[last] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@@ -1,11 +1,26 @@
|
|||||||
|
import type { InternalHelpers, LayoutData, RenderOptions, SVG, SVGGroup } from 'mermaid';
|
||||||
|
// @ts-ignore TODO: Investigate D3 issue
|
||||||
import { curveLinear } from 'd3';
|
import { curveLinear } from 'd3';
|
||||||
import ELK from 'elkjs/lib/elk.bundled.js';
|
import ELK from 'elkjs/lib/elk.bundled.js';
|
||||||
import type { InternalHelpers, LayoutData, RenderOptions, SVG, SVGGroup } from 'mermaid';
|
|
||||||
import { type TreeData, findCommonAncestor } from './find-common-ancestor.js';
|
import { type TreeData, findCommonAncestor } from './find-common-ancestor.js';
|
||||||
|
|
||||||
|
import {
|
||||||
|
type P,
|
||||||
|
type RectLike,
|
||||||
|
outsideNode,
|
||||||
|
computeNodeIntersection,
|
||||||
|
replaceEndpoint,
|
||||||
|
onBorder,
|
||||||
|
} from './geometry.js';
|
||||||
|
|
||||||
type Node = LayoutData['nodes'][number];
|
type Node = LayoutData['nodes'][number];
|
||||||
// Used to calculate distances in order to avoid floating number rounding issues when comparing floating numbers
|
|
||||||
const epsilon = 0.0001;
|
// Minimal structural type to avoid depending on d3 Selection typings
|
||||||
|
interface D3Selection<T extends Element> {
|
||||||
|
node(): T | null;
|
||||||
|
attr(name: string, value: string): D3Selection<T>;
|
||||||
|
}
|
||||||
|
|
||||||
interface LabelData {
|
interface LabelData {
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
@@ -16,18 +31,9 @@ interface LabelData {
|
|||||||
interface NodeWithVertex extends Omit<Node, 'domId'> {
|
interface NodeWithVertex extends Omit<Node, 'domId'> {
|
||||||
children?: LayoutData['nodes'];
|
children?: LayoutData['nodes'];
|
||||||
labelData?: LabelData;
|
labelData?: LabelData;
|
||||||
domId?: Node['domId'] | SVGGroup | d3.Selection<SVGAElement, unknown, Element | null, unknown>;
|
domId?: D3Selection<SVGAElement | SVGGElement>;
|
||||||
}
|
|
||||||
interface Point {
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
}
|
|
||||||
function distance(p1?: Point, p2?: Point): number {
|
|
||||||
if (!p1 || !p2) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const render = async (
|
export const render = async (
|
||||||
data4Layout: LayoutData,
|
data4Layout: LayoutData,
|
||||||
svg: SVG,
|
svg: SVG,
|
||||||
@@ -61,39 +67,26 @@ export const render = async (
|
|||||||
|
|
||||||
// Add the element to the DOM
|
// Add the element to the DOM
|
||||||
if (!node.isGroup) {
|
if (!node.isGroup) {
|
||||||
// Create a clean node object for ELK with only the properties it expects
|
const child = node as NodeWithVertex;
|
||||||
const child: NodeWithVertex = {
|
|
||||||
id: node.id,
|
|
||||||
width: node.width,
|
|
||||||
height: node.height,
|
|
||||||
// Store the original node data for later use
|
|
||||||
label: node.label,
|
|
||||||
isGroup: node.isGroup,
|
|
||||||
shape: node.shape,
|
|
||||||
padding: node.padding,
|
|
||||||
cssClasses: node.cssClasses,
|
|
||||||
cssStyles: node.cssStyles,
|
|
||||||
look: node.look,
|
|
||||||
// Include parentId for subgraph processing
|
|
||||||
parentId: node.parentId,
|
|
||||||
};
|
|
||||||
graph.children.push(child);
|
graph.children.push(child);
|
||||||
nodeDb[node.id] = child;
|
nodeDb[node.id] = node;
|
||||||
|
|
||||||
const childNodeEl = await insertNode(nodeEl, node, { config, dir: node.dir });
|
const childNodeEl = await insertNode(nodeEl, node, { config, dir: node.dir });
|
||||||
const boundingBox = childNodeEl.node()!.getBBox();
|
const boundingBox = childNodeEl.node()!.getBBox();
|
||||||
// Store the domId separately for rendering, not in the ELK graph
|
// Store the domId separately for rendering, not in the ELK graph
|
||||||
child.domId = childNodeEl;
|
child.domId = childNodeEl;
|
||||||
child.calcIntersect = node.calcIntersect;
|
|
||||||
child.width = boundingBox.width;
|
child.width = boundingBox.width;
|
||||||
child.height = boundingBox.height;
|
child.height = boundingBox.height;
|
||||||
} else {
|
} else {
|
||||||
// A subgraph
|
// A subgraph
|
||||||
const child: NodeWithVertex & { children: NodeWithVertex[] } = {
|
const child: NodeWithVertex & { children: NodeWithVertex[] } = {
|
||||||
...node,
|
...node,
|
||||||
|
domId: undefined,
|
||||||
children: [],
|
children: [],
|
||||||
};
|
};
|
||||||
|
// Let elk render with the copy
|
||||||
graph.children.push(child);
|
graph.children.push(child);
|
||||||
|
// Save the original containing the intersection function
|
||||||
nodeDb[node.id] = child;
|
nodeDb[node.id] = child;
|
||||||
await addVertices(nodeEl, nodeArr, child, node.id);
|
await addVertices(nodeEl, nodeArr, child, node.id);
|
||||||
|
|
||||||
@@ -168,7 +161,7 @@ export const render = async (
|
|||||||
height: node.height,
|
height: node.height,
|
||||||
};
|
};
|
||||||
if (node.isGroup) {
|
if (node.isGroup) {
|
||||||
log.debug('id abc88 subgraph = ', node.id, node.x, node.y, node.labelData);
|
log.debug('Id abc88 subgraph = ', node.id, node.x, node.y, node.labelData);
|
||||||
const subgraphEl = subgraphsEl.insert('g').attr('class', 'subgraph');
|
const subgraphEl = subgraphsEl.insert('g').attr('class', 'subgraph');
|
||||||
// TODO use faster way of cloning
|
// TODO use faster way of cloning
|
||||||
const clusterNode = JSON.parse(JSON.stringify(node));
|
const clusterNode = JSON.parse(JSON.stringify(node));
|
||||||
@@ -177,10 +170,10 @@ export const render = async (
|
|||||||
clusterNode.width = Math.max(clusterNode.width, node.labelData.width);
|
clusterNode.width = Math.max(clusterNode.width, node.labelData.width);
|
||||||
await insertCluster(subgraphEl, clusterNode);
|
await insertCluster(subgraphEl, clusterNode);
|
||||||
|
|
||||||
log.debug('id (UIO)= ', node.id, node.width, node.shape, node.labels);
|
log.debug('Id (UIO)= ', node.id, node.width, node.shape, node.labels);
|
||||||
} else {
|
} else {
|
||||||
log.info(
|
log.info(
|
||||||
'id NODE = ',
|
'Id NODE = ',
|
||||||
node.id,
|
node.id,
|
||||||
node.x,
|
node.x,
|
||||||
node.y,
|
node.y,
|
||||||
@@ -222,25 +215,19 @@ export const render = async (
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
subgraphs.forEach(function (subgraph: { id: string | number }) {
|
|
||||||
const data: any = { id: subgraph.id };
|
|
||||||
if (parentLookupDb.parentById[subgraph.id] !== undefined) {
|
|
||||||
data.parent = parentLookupDb.parentById[subgraph.id];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return parentLookupDb;
|
return parentLookupDb;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getEdgeStartEndPoint = (edge: any) => {
|
const getEdgeStartEndPoint = (edge: any) => {
|
||||||
const source: any = edge.start;
|
// edge.start and edge.end are IDs (string/number) in our layout data
|
||||||
const target: any = edge.end;
|
const sourceId: string | number = edge.start;
|
||||||
|
const targetId: string | number = edge.end;
|
||||||
|
|
||||||
// Save the original source and target
|
const source = sourceId;
|
||||||
const sourceId = source;
|
const target = targetId;
|
||||||
const targetId = target;
|
|
||||||
|
|
||||||
const startNode = nodeDb[edge.start.id];
|
const startNode = nodeDb[sourceId];
|
||||||
const endNode = nodeDb[edge.end.id];
|
const endNode = nodeDb[targetId];
|
||||||
|
|
||||||
if (!startNode || !endNode) {
|
if (!startNode || !endNode) {
|
||||||
return { source, target };
|
return { source, target };
|
||||||
@@ -263,6 +250,112 @@ export const render = async (
|
|||||||
/**
|
/**
|
||||||
* Add edges to graph based on parsed graph definition
|
* Add edges to graph based on parsed graph definition
|
||||||
*/
|
*/
|
||||||
|
// Edge helper maps and utilities (de-duplicated)
|
||||||
|
const ARROW_MAP: Record<string, [string, string]> = {
|
||||||
|
arrow_open: ['arrow_open', 'arrow_open'],
|
||||||
|
arrow_cross: ['arrow_open', 'arrow_cross'],
|
||||||
|
double_arrow_cross: ['arrow_cross', 'arrow_cross'],
|
||||||
|
arrow_point: ['arrow_open', 'arrow_point'],
|
||||||
|
double_arrow_point: ['arrow_point', 'arrow_point'],
|
||||||
|
arrow_circle: ['arrow_open', 'arrow_circle'],
|
||||||
|
double_arrow_circle: ['arrow_circle', 'arrow_circle'],
|
||||||
|
};
|
||||||
|
|
||||||
|
const computeStroke = (
|
||||||
|
stroke: string | undefined,
|
||||||
|
defaultStyle?: string,
|
||||||
|
defaultLabelStyle?: string
|
||||||
|
) => {
|
||||||
|
// Defaults correspond to 'normal'
|
||||||
|
let thickness = 'normal';
|
||||||
|
let pattern = 'solid';
|
||||||
|
let style = '';
|
||||||
|
let labelStyle = '';
|
||||||
|
|
||||||
|
if (stroke === 'dotted') {
|
||||||
|
pattern = 'dotted';
|
||||||
|
style = 'fill:none;stroke-width:2px;stroke-dasharray:3;';
|
||||||
|
} else if (stroke === 'thick') {
|
||||||
|
thickness = 'thick';
|
||||||
|
style = 'stroke-width: 3.5px;fill:none;';
|
||||||
|
} else {
|
||||||
|
// normal
|
||||||
|
style = defaultStyle ?? 'fill:none;';
|
||||||
|
if (defaultLabelStyle !== undefined) {
|
||||||
|
labelStyle = defaultLabelStyle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { thickness, pattern, style, labelStyle };
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCurve = (edgeInterpolate: any, edgesDefaultInterpolate: any, confCurve: any) => {
|
||||||
|
if (edgeInterpolate !== undefined) {
|
||||||
|
return interpolateToCurve(edgeInterpolate, curveLinear);
|
||||||
|
}
|
||||||
|
if (edgesDefaultInterpolate !== undefined) {
|
||||||
|
return interpolateToCurve(edgesDefaultInterpolate, curveLinear);
|
||||||
|
}
|
||||||
|
// @ts-ignore TODO: fix this
|
||||||
|
return interpolateToCurve(confCurve, curveLinear);
|
||||||
|
};
|
||||||
|
const buildEdgeData = (
|
||||||
|
edge: any,
|
||||||
|
defaults: {
|
||||||
|
defaultStyle?: string;
|
||||||
|
defaultLabelStyle?: string;
|
||||||
|
defaultInterpolate?: any;
|
||||||
|
confCurve: any;
|
||||||
|
},
|
||||||
|
common: any
|
||||||
|
) => {
|
||||||
|
const edgeData: any = { style: '', labelStyle: '' };
|
||||||
|
edgeData.minlen = edge.length || 1;
|
||||||
|
// maintain legacy behavior
|
||||||
|
edge.text = edge.label;
|
||||||
|
|
||||||
|
// Arrowhead fill vs none
|
||||||
|
edgeData.arrowhead = edge.type === 'arrow_open' ? 'none' : 'normal';
|
||||||
|
|
||||||
|
// Arrow types
|
||||||
|
const arrowMap = ARROW_MAP[edge.type] ?? ARROW_MAP.arrow_open;
|
||||||
|
edgeData.arrowTypeStart = arrowMap[0];
|
||||||
|
edgeData.arrowTypeEnd = arrowMap[1];
|
||||||
|
|
||||||
|
// Optional edge label positioning flags
|
||||||
|
edgeData.startLabelRight = edge.startLabelRight;
|
||||||
|
edgeData.endLabelLeft = edge.endLabelLeft;
|
||||||
|
|
||||||
|
// Stroke
|
||||||
|
const strokeRes = computeStroke(edge.stroke, defaults.defaultStyle, defaults.defaultLabelStyle);
|
||||||
|
edgeData.thickness = strokeRes.thickness;
|
||||||
|
edgeData.pattern = strokeRes.pattern;
|
||||||
|
edgeData.style = (edgeData.style || '') + (strokeRes.style || '');
|
||||||
|
edgeData.labelStyle = (edgeData.labelStyle || '') + (strokeRes.labelStyle || '');
|
||||||
|
|
||||||
|
// Curve
|
||||||
|
// @ts-ignore - defaults.confCurve is present at runtime but missing in type
|
||||||
|
edgeData.curve = getCurve(edge.interpolate, defaults.defaultInterpolate, defaults.confCurve);
|
||||||
|
|
||||||
|
// Arrowhead style + labelpos when we have label text
|
||||||
|
const hasText = (edge?.text ?? '') !== '';
|
||||||
|
if (hasText) {
|
||||||
|
edgeData.arrowheadStyle = 'fill: #333';
|
||||||
|
edgeData.labelpos = 'c';
|
||||||
|
} else if (edge.style !== undefined) {
|
||||||
|
edgeData.arrowheadStyle = 'fill: #333';
|
||||||
|
}
|
||||||
|
|
||||||
|
edgeData.labelType = edge.labelType;
|
||||||
|
edgeData.label = (edge?.text ?? '').replace(common.lineBreakRegex, '\n');
|
||||||
|
|
||||||
|
if (edge.style === undefined) {
|
||||||
|
edgeData.style = edgeData.style ?? 'stroke: #333; stroke-width: 1.5px;fill:none;';
|
||||||
|
}
|
||||||
|
|
||||||
|
edgeData.labelStyle = edgeData.labelStyle.replace('color:', 'fill:');
|
||||||
|
return edgeData;
|
||||||
|
};
|
||||||
|
|
||||||
const addEdges = async function (
|
const addEdges = async function (
|
||||||
dataForLayout: { edges: any; direction?: string },
|
dataForLayout: { edges: any; direction?: string },
|
||||||
graph: {
|
graph: {
|
||||||
@@ -284,7 +377,6 @@ export const render = async (
|
|||||||
const edges = dataForLayout.edges;
|
const edges = dataForLayout.edges;
|
||||||
const labelsEl = svg.insert('g').attr('class', 'edgeLabels');
|
const labelsEl = svg.insert('g').attr('class', 'edgeLabels');
|
||||||
const linkIdCnt: any = {};
|
const linkIdCnt: any = {};
|
||||||
const dir = dataForLayout.direction || 'DOWN';
|
|
||||||
let defaultStyle: string | undefined;
|
let defaultStyle: string | undefined;
|
||||||
let defaultLabelStyle: string | undefined;
|
let defaultLabelStyle: string | undefined;
|
||||||
|
|
||||||
@@ -314,105 +406,24 @@ export const render = async (
|
|||||||
linkIdCnt[linkIdBase]++;
|
linkIdCnt[linkIdBase]++;
|
||||||
log.info('abc78 new entry', linkIdBase, linkIdCnt[linkIdBase]);
|
log.info('abc78 new entry', linkIdBase, linkIdCnt[linkIdBase]);
|
||||||
}
|
}
|
||||||
const linkId = linkIdBase + '_' + linkIdCnt[linkIdBase];
|
const linkId = linkIdBase; // + '_' + linkIdCnt[linkIdBase];
|
||||||
edge.id = linkId;
|
edge.id = linkId;
|
||||||
log.info('abc78 new link id to be used is', linkIdBase, linkId, linkIdCnt[linkIdBase]);
|
log.info('abc78 new link id to be used is', linkIdBase, linkId, linkIdCnt[linkIdBase]);
|
||||||
const linkNameStart = 'LS_' + edge.start;
|
const linkNameStart = 'LS_' + edge.start;
|
||||||
const linkNameEnd = 'LE_' + edge.end;
|
const linkNameEnd = 'LE_' + edge.end;
|
||||||
|
|
||||||
const edgeData: any = { style: '', labelStyle: '' };
|
|
||||||
edgeData.minlen = edge.length || 1;
|
|
||||||
edge.text = edge.label;
|
|
||||||
// Set link type for rendering
|
|
||||||
if (edge.type === 'arrow_open') {
|
|
||||||
edgeData.arrowhead = 'none';
|
|
||||||
} else {
|
|
||||||
edgeData.arrowhead = 'normal';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check of arrow types, placed here in order not to break old rendering
|
|
||||||
edgeData.arrowTypeStart = 'arrow_open';
|
|
||||||
edgeData.arrowTypeEnd = 'arrow_open';
|
|
||||||
|
|
||||||
/* eslint-disable no-fallthrough */
|
|
||||||
switch (edge.type) {
|
|
||||||
case 'double_arrow_cross':
|
|
||||||
edgeData.arrowTypeStart = 'arrow_cross';
|
|
||||||
case 'arrow_cross':
|
|
||||||
edgeData.arrowTypeEnd = 'arrow_cross';
|
|
||||||
break;
|
|
||||||
case 'double_arrow_point':
|
|
||||||
edgeData.arrowTypeStart = 'arrow_point';
|
|
||||||
case 'arrow_point':
|
|
||||||
edgeData.arrowTypeEnd = 'arrow_point';
|
|
||||||
break;
|
|
||||||
case 'double_arrow_circle':
|
|
||||||
edgeData.arrowTypeStart = 'arrow_circle';
|
|
||||||
case 'arrow_circle':
|
|
||||||
edgeData.arrowTypeEnd = 'arrow_circle';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
let style = '';
|
|
||||||
let labelStyle = '';
|
|
||||||
|
|
||||||
edgeData.startLabelRight = edge.startLabelRight;
|
|
||||||
edgeData.endLabelLeft = edge.endLabelLeft;
|
|
||||||
|
|
||||||
switch (edge.stroke) {
|
|
||||||
case 'normal':
|
|
||||||
style = 'fill:none;';
|
|
||||||
if (defaultStyle !== undefined) {
|
|
||||||
style = defaultStyle;
|
|
||||||
}
|
|
||||||
if (defaultLabelStyle !== undefined) {
|
|
||||||
labelStyle = defaultLabelStyle;
|
|
||||||
}
|
|
||||||
edgeData.thickness = 'normal';
|
|
||||||
edgeData.pattern = 'solid';
|
|
||||||
break;
|
|
||||||
case 'dotted':
|
|
||||||
edgeData.thickness = 'normal';
|
|
||||||
edgeData.pattern = 'dotted';
|
|
||||||
edgeData.style = 'fill:none;stroke-width:2px;stroke-dasharray:3;';
|
|
||||||
break;
|
|
||||||
case 'thick':
|
|
||||||
edgeData.thickness = 'thick';
|
|
||||||
edgeData.pattern = 'solid';
|
|
||||||
edgeData.style = 'stroke-width: 3.5px;fill:none;';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
edgeData.style = edgeData.style += style;
|
|
||||||
edgeData.labelStyle = edgeData.labelStyle += labelStyle;
|
|
||||||
|
|
||||||
const conf = getConfig();
|
const conf = getConfig();
|
||||||
if (edge.interpolate !== undefined) {
|
const edgeData = buildEdgeData(
|
||||||
edgeData.curve = interpolateToCurve(edge.interpolate, curveLinear);
|
edge,
|
||||||
} else if (edges.defaultInterpolate !== undefined) {
|
{
|
||||||
edgeData.curve = interpolateToCurve(edges.defaultInterpolate, curveLinear);
|
defaultStyle,
|
||||||
} else {
|
defaultLabelStyle,
|
||||||
// @ts-ignore TODO: fix this
|
defaultInterpolate: edges.defaultInterpolate,
|
||||||
edgeData.curve = interpolateToCurve(conf.curve, curveLinear);
|
// @ts-ignore - conf.curve exists at runtime but is missing from typing
|
||||||
}
|
confCurve: conf.curve,
|
||||||
|
},
|
||||||
if (edge.text === undefined) {
|
common
|
||||||
if (edge.style !== undefined) {
|
);
|
||||||
edgeData.arrowheadStyle = 'fill: #333';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
edgeData.arrowheadStyle = 'fill: #333';
|
|
||||||
edgeData.labelpos = 'c';
|
|
||||||
}
|
|
||||||
|
|
||||||
edgeData.labelType = edge.labelType;
|
|
||||||
edgeData.label = (edge?.text || '').replace(common.lineBreakRegex, '\n');
|
|
||||||
|
|
||||||
if (edge.style === undefined) {
|
|
||||||
edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none;';
|
|
||||||
}
|
|
||||||
|
|
||||||
edgeData.labelStyle = edgeData.labelStyle.replace('color:', 'fill:');
|
|
||||||
|
|
||||||
edgeData.id = linkId;
|
edgeData.id = linkId;
|
||||||
edgeData.classes = 'flowchart-link ' + linkNameStart + ' ' + linkNameEnd;
|
edgeData.classes = 'flowchart-link ' + linkNameStart + ' ' + linkNameEnd;
|
||||||
@@ -421,13 +432,11 @@ export const render = async (
|
|||||||
|
|
||||||
// calculate start and end points of the edge, note that the source and target
|
// calculate start and end points of the edge, note that the source and target
|
||||||
// can be modified for shapes that have ports
|
// can be modified for shapes that have ports
|
||||||
// @ts-ignore TODO: fix this
|
|
||||||
const { source, target, sourceId, targetId } = getEdgeStartEndPoint(edge, dir);
|
const { source, target, sourceId, targetId } = getEdgeStartEndPoint(edge);
|
||||||
log.debug('abc78 source and target', source, target);
|
log.debug('abc78 source and target', source, target);
|
||||||
// Add the edge to the graph
|
// Add the edge to the graph
|
||||||
graph.edges.push({
|
graph.edges.push({
|
||||||
// @ts-ignore TODO: fix this
|
|
||||||
id: 'e' + edge.start + edge.end,
|
|
||||||
...edge,
|
...edge,
|
||||||
sources: [source],
|
sources: [source],
|
||||||
targets: [target],
|
targets: [target],
|
||||||
@@ -461,6 +470,7 @@ export const render = async (
|
|||||||
case 'RL':
|
case 'RL':
|
||||||
return 'LEFT';
|
return 'LEFT';
|
||||||
case 'TB':
|
case 'TB':
|
||||||
|
case 'TD': // TD is an alias for TB in Mermaid
|
||||||
return 'DOWN';
|
return 'DOWN';
|
||||||
case 'BT':
|
case 'BT':
|
||||||
return 'UP';
|
return 'UP';
|
||||||
@@ -484,6 +494,203 @@ export const render = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Node bounds helpers (global)
|
||||||
|
const getEffectiveGroupWidth = (node: any): number => {
|
||||||
|
const labelW = node?.labels?.[0]?.width ?? 0;
|
||||||
|
const padding = node?.padding ?? 0;
|
||||||
|
return Math.max(node.width ?? 0, labelW + padding);
|
||||||
|
};
|
||||||
|
|
||||||
|
const boundsFor = (node: any): RectLike => {
|
||||||
|
const width = node?.isGroup ? getEffectiveGroupWidth(node) : node.width;
|
||||||
|
return {
|
||||||
|
x: node.offset.posX + node.width / 2,
|
||||||
|
y: node.offset.posY + node.height / 2,
|
||||||
|
width,
|
||||||
|
height: node.height,
|
||||||
|
padding: node.padding,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
// Helper utilities for endpoint handling around cutter2
|
||||||
|
type Side = 'start' | 'end';
|
||||||
|
const approxEq = (a: number, b: number, eps = 1e-6) => Math.abs(a - b) < eps;
|
||||||
|
const isCenterApprox = (pt: P, node: { x: number; y: number }) =>
|
||||||
|
approxEq(pt.x, node.x) && approxEq(pt.y, node.y);
|
||||||
|
|
||||||
|
const getCandidateBorderPoint = (
|
||||||
|
points: P[],
|
||||||
|
node: any,
|
||||||
|
side: Side
|
||||||
|
): { candidate: P; centerApprox: boolean } => {
|
||||||
|
if (!points?.length) {
|
||||||
|
return { candidate: { x: node.x, y: node.y } as P, centerApprox: true };
|
||||||
|
}
|
||||||
|
if (side === 'start') {
|
||||||
|
const first = points[0];
|
||||||
|
const centerApprox = isCenterApprox(first, node);
|
||||||
|
const candidate = centerApprox && points.length > 1 ? points[1] : first;
|
||||||
|
return { candidate, centerApprox };
|
||||||
|
} else {
|
||||||
|
const last = points[points.length - 1];
|
||||||
|
const centerApprox = isCenterApprox(last, node);
|
||||||
|
const candidate = centerApprox && points.length > 1 ? points[points.length - 2] : last;
|
||||||
|
return { candidate, centerApprox };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const dropAutoCenterPoint = (points: P[], side: Side, doDrop: boolean) => {
|
||||||
|
if (!doDrop) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (side === 'start') {
|
||||||
|
if (points.length > 0) {
|
||||||
|
points.shift();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (points.length > 0) {
|
||||||
|
points.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const applyStartIntersectionIfNeeded = (points: P[], startNode: any, startBounds: RectLike) => {
|
||||||
|
let firstOutsideStartIndex = -1;
|
||||||
|
for (const [i, p] of points.entries()) {
|
||||||
|
if (outsideNode(startBounds, p)) {
|
||||||
|
firstOutsideStartIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (firstOutsideStartIndex !== -1) {
|
||||||
|
const outsidePointForStart = points[firstOutsideStartIndex];
|
||||||
|
const startCenter = points[0];
|
||||||
|
const startIntersection = computeNodeIntersection(
|
||||||
|
startNode,
|
||||||
|
startBounds,
|
||||||
|
outsidePointForStart,
|
||||||
|
startCenter
|
||||||
|
);
|
||||||
|
replaceEndpoint(points, 'start', startIntersection);
|
||||||
|
log.debug('UIO cutter2: start-only intersection applied', { startIntersection });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const applyEndIntersectionIfNeeded = (points: P[], endNode: any, endBounds: RectLike) => {
|
||||||
|
let outsideIndexForEnd = -1;
|
||||||
|
for (let i = points.length - 1; i >= 0; i--) {
|
||||||
|
if (outsideNode(endBounds, points[i])) {
|
||||||
|
outsideIndexForEnd = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (outsideIndexForEnd !== -1) {
|
||||||
|
const outsidePointForEnd = points[outsideIndexForEnd];
|
||||||
|
const endCenter = points[points.length - 1];
|
||||||
|
const endIntersection = computeNodeIntersection(
|
||||||
|
endNode,
|
||||||
|
endBounds,
|
||||||
|
outsidePointForEnd,
|
||||||
|
endCenter
|
||||||
|
);
|
||||||
|
replaceEndpoint(points, 'end', endIntersection);
|
||||||
|
log.debug('UIO cutter2: end-only intersection applied', { endIntersection });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const cutter2 = (startNode: any, endNode: any, _points: any[]) => {
|
||||||
|
const startBounds = boundsFor(startNode);
|
||||||
|
const endBounds = boundsFor(endNode);
|
||||||
|
|
||||||
|
if (_points.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the original points array
|
||||||
|
const points: P[] = [..._points] as P[];
|
||||||
|
|
||||||
|
// The first point is the center of sNode, the last point is the center of eNode
|
||||||
|
const startCenter = points[0];
|
||||||
|
const endCenter = points[points.length - 1];
|
||||||
|
|
||||||
|
// Minimal, structured logging for diagnostics
|
||||||
|
log.debug('PPP cutter2: bounds', { startBounds, endBounds });
|
||||||
|
log.debug('PPP cutter2: original points', _points);
|
||||||
|
|
||||||
|
let firstOutsideStartIndex = -1;
|
||||||
|
|
||||||
|
// Single iteration through the array
|
||||||
|
for (const [i, point] of points.entries()) {
|
||||||
|
if (firstOutsideStartIndex === -1 && outsideNode(startBounds, point)) {
|
||||||
|
firstOutsideStartIndex = i;
|
||||||
|
}
|
||||||
|
if (outsideNode(endBounds, point)) {
|
||||||
|
// keep scanning; we'll also scan from the end for the last outside point
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate intersection with start node if we found a point outside it
|
||||||
|
if (firstOutsideStartIndex !== -1) {
|
||||||
|
const outsidePointForStart = points[firstOutsideStartIndex];
|
||||||
|
const startIntersection = computeNodeIntersection(
|
||||||
|
startNode,
|
||||||
|
startBounds,
|
||||||
|
outsidePointForStart,
|
||||||
|
startCenter
|
||||||
|
);
|
||||||
|
log.debug('UIO cutter2: start intersection', startIntersection);
|
||||||
|
replaceEndpoint(points, 'start', startIntersection);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate intersection with end node
|
||||||
|
let outsidePointForEnd = null;
|
||||||
|
let outsideIndexForEnd = -1;
|
||||||
|
|
||||||
|
for (let i = points.length - 1; i >= 0; i--) {
|
||||||
|
if (outsideNode(endBounds, points[i])) {
|
||||||
|
outsidePointForEnd = points[i];
|
||||||
|
outsideIndexForEnd = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!outsidePointForEnd && points.length > 1) {
|
||||||
|
outsidePointForEnd = points[points.length - 2];
|
||||||
|
outsideIndexForEnd = points.length - 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outsidePointForEnd) {
|
||||||
|
const endIntersection = computeNodeIntersection(
|
||||||
|
endNode,
|
||||||
|
endBounds,
|
||||||
|
outsidePointForEnd,
|
||||||
|
endCenter
|
||||||
|
);
|
||||||
|
log.debug('UIO cutter2: end intersection', { endIntersection, outsideIndexForEnd });
|
||||||
|
replaceEndpoint(points, 'end', endIntersection);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final cleanup: Check if the last point is too close to the previous point
|
||||||
|
if (points.length > 1) {
|
||||||
|
const lastPoint = points[points.length - 1];
|
||||||
|
const secondLastPoint = points[points.length - 2];
|
||||||
|
const distance = Math.sqrt(
|
||||||
|
(lastPoint.x - secondLastPoint.x) ** 2 + (lastPoint.y - secondLastPoint.y) ** 2
|
||||||
|
);
|
||||||
|
if (distance < 2) {
|
||||||
|
log.debug('UIO cutter2: trimming tail point (too close)', {
|
||||||
|
distance,
|
||||||
|
lastPoint,
|
||||||
|
secondLastPoint,
|
||||||
|
});
|
||||||
|
points.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug('UIO cutter2: final points', points);
|
||||||
|
|
||||||
|
return points;
|
||||||
|
};
|
||||||
|
|
||||||
// @ts-ignore - ELK is not typed
|
// @ts-ignore - ELK is not typed
|
||||||
const elk = new ELK();
|
const elk = new ELK();
|
||||||
const element = svg.select('g');
|
const element = svg.select('g');
|
||||||
@@ -495,17 +702,19 @@ export const render = async (
|
|||||||
id: 'root',
|
id: 'root',
|
||||||
layoutOptions: {
|
layoutOptions: {
|
||||||
'elk.hierarchyHandling': 'INCLUDE_CHILDREN',
|
'elk.hierarchyHandling': 'INCLUDE_CHILDREN',
|
||||||
'elk.layered.crossingMinimization.forceNodeModelOrder':
|
|
||||||
data4Layout.config.elk?.forceNodeModelOrder,
|
|
||||||
'elk.layered.considerModelOrder.strategy': data4Layout.config.elk?.considerModelOrder,
|
|
||||||
|
|
||||||
'elk.algorithm': algorithm,
|
'elk.algorithm': algorithm,
|
||||||
'nodePlacement.strategy': data4Layout.config.elk?.nodePlacementStrategy,
|
'nodePlacement.strategy': data4Layout.config.elk?.nodePlacementStrategy,
|
||||||
'elk.layered.mergeEdges': data4Layout.config.elk?.mergeEdges,
|
'elk.layered.mergeEdges': data4Layout.config.elk?.mergeEdges,
|
||||||
'elk.direction': 'DOWN',
|
'elk.direction': 'DOWN',
|
||||||
'spacing.baseValue': 35,
|
'spacing.baseValue': 40,
|
||||||
|
'elk.layered.crossingMinimization.forceNodeModelOrder':
|
||||||
|
data4Layout.config.elk?.forceNodeModelOrder,
|
||||||
|
'elk.layered.considerModelOrder.strategy': data4Layout.config.elk?.considerModelOrder,
|
||||||
'elk.layered.unnecessaryBendpoints': true,
|
'elk.layered.unnecessaryBendpoints': true,
|
||||||
'elk.layered.cycleBreaking.strategy': data4Layout.config.elk?.cycleBreakingStrategy,
|
'elk.layered.cycleBreaking.strategy': data4Layout.config.elk?.cycleBreakingStrategy,
|
||||||
|
|
||||||
|
// 'elk.layered.cycleBreaking.strategy': 'GREEDY_MODEL_ORDER',
|
||||||
|
// 'elk.layered.cycleBreaking.strategy': 'MODEL_ORDER',
|
||||||
// 'spacing.nodeNode': 20,
|
// 'spacing.nodeNode': 20,
|
||||||
// 'spacing.nodeNodeBetweenLayers': 25,
|
// 'spacing.nodeNodeBetweenLayers': 25,
|
||||||
// 'spacing.edgeNode': 20,
|
// 'spacing.edgeNode': 20,
|
||||||
@@ -513,22 +722,28 @@ export const render = async (
|
|||||||
// 'spacing.edgeEdge': 10,
|
// 'spacing.edgeEdge': 10,
|
||||||
// 'spacing.edgeEdgeBetweenLayers': 20,
|
// 'spacing.edgeEdgeBetweenLayers': 20,
|
||||||
// 'spacing.nodeSelfLoop': 20,
|
// 'spacing.nodeSelfLoop': 20,
|
||||||
|
|
||||||
// Tweaking options
|
// Tweaking options
|
||||||
|
// 'nodePlacement.favorStraightEdges': true,
|
||||||
// 'elk.layered.nodePlacement.favorStraightEdges': true,
|
// 'elk.layered.nodePlacement.favorStraightEdges': true,
|
||||||
// 'nodePlacement.feedbackEdges': true,
|
// 'nodePlacement.feedbackEdges': true,
|
||||||
// 'elk.layered.wrapping.multiEdge.improveCuts': true,
|
'elk.layered.wrapping.multiEdge.improveCuts': true,
|
||||||
// 'elk.layered.wrapping.multiEdge.improveWrappedEdges': true,
|
'elk.layered.wrapping.multiEdge.improveWrappedEdges': true,
|
||||||
// 'elk.layered.wrapping.strategy': 'MULTI_EDGE',
|
// 'elk.layered.wrapping.strategy': 'MULTI_EDGE',
|
||||||
// 'elk.layered.edgeRouting.selfLoopDistribution': 'EQUALLY',
|
// 'elk.layered.wrapping.strategy': 'SINGLE_EDGE',
|
||||||
// 'elk.layered.mergeHierarchyEdges': true,
|
'elk.layered.edgeRouting.selfLoopDistribution': 'EQUALLY',
|
||||||
|
'elk.layered.mergeHierarchyEdges': true,
|
||||||
|
|
||||||
// 'elk.layered.feedbackEdges': true,
|
// 'elk.layered.feedbackEdges': true,
|
||||||
// 'elk.layered.crossingMinimization.semiInteractive': true,
|
// 'elk.layered.crossingMinimization.semiInteractive': true,
|
||||||
// 'elk.layered.edgeRouting.splines.sloppy.layerSpacingFactor': 1,
|
// 'elk.layered.edgeRouting.splines.sloppy.layerSpacingFactor': 1,
|
||||||
// 'elk.layered.edgeRouting.polyline.slopedEdgeZoneWidth': 4.0,
|
// 'elk.layered.edgeRouting.polyline.slopedEdgeZoneWidth': 4.0,
|
||||||
// 'elk.layered.wrapping.validify.strategy': 'LOOK_BACK',
|
// 'elk.layered.wrapping.validify.strategy': 'LOOK_BACK',
|
||||||
// 'elk.insideSelfLoops.activate': true,
|
// 'elk.insideSelfLoops.activate': true,
|
||||||
|
// 'elk.separateConnectedComponents': true,
|
||||||
// 'elk.alg.layered.options.EdgeStraighteningStrategy': 'NONE',
|
// 'elk.alg.layered.options.EdgeStraighteningStrategy': 'NONE',
|
||||||
// 'elk.layered.considerModelOrder.strategy': 'NODES_AND_EDGES', // NODES_AND_EDGES
|
// 'elk.layered.considerModelOrder.strategy': 'NODES_AND_EDGES', // NODES_AND_EDGES
|
||||||
|
// 'elk.layered.considerModelOrder.strategy': 'EDGES', // NODES_AND_EDGES
|
||||||
// 'elk.layered.wrapping.cutting.strategy': 'ARD', // NODES_AND_EDGES
|
// 'elk.layered.wrapping.cutting.strategy': 'ARD', // NODES_AND_EDGES
|
||||||
},
|
},
|
||||||
children: [],
|
children: [],
|
||||||
@@ -538,7 +753,7 @@ export const render = async (
|
|||||||
log.info('Drawing flowchart using v4 renderer', elk);
|
log.info('Drawing flowchart using v4 renderer', elk);
|
||||||
|
|
||||||
// Set the direction of the graph based on the parsed information
|
// Set the direction of the graph based on the parsed information
|
||||||
const dir = data4Layout.direction || 'DOWN';
|
const dir = data4Layout.direction ?? 'DOWN';
|
||||||
elkGraph.layoutOptions['elk.direction'] = dir2ElkDirection(dir);
|
elkGraph.layoutOptions['elk.direction'] = dir2ElkDirection(dir);
|
||||||
|
|
||||||
// Create the lookup db for the subgraphs and their children to used when creating
|
// Create the lookup db for the subgraphs and their children to used when creating
|
||||||
@@ -569,15 +784,16 @@ export const render = async (
|
|||||||
|
|
||||||
// Subgraph
|
// Subgraph
|
||||||
if (parentLookupDb.childrenById[node.id] !== undefined) {
|
if (parentLookupDb.childrenById[node.id] !== undefined) {
|
||||||
|
// Set label and adjust node width separately (avoid side effects in labels array)
|
||||||
node.labels = [
|
node.labels = [
|
||||||
{
|
{
|
||||||
text: node.label,
|
text: node.label,
|
||||||
width: node?.labelData?.width || 50,
|
width: node?.labelData?.width ?? 50,
|
||||||
height: node?.labelData?.height || 50,
|
height: node?.labelData?.height ?? 50,
|
||||||
},
|
},
|
||||||
(node.width = node.width + 2 * node.padding),
|
|
||||||
log.debug('UIO node label', node?.labelData?.width, node.padding),
|
|
||||||
];
|
];
|
||||||
|
node.width = node.width + 2 * node.padding;
|
||||||
|
log.debug('UIO node label', node?.labelData?.width, node.padding);
|
||||||
node.layoutOptions = {
|
node.layoutOptions = {
|
||||||
'spacing.baseValue': 30,
|
'spacing.baseValue': 30,
|
||||||
'nodeLabels.placement': '[H_CENTER V_TOP, INSIDE]',
|
'nodeLabels.placement': '[H_CENTER V_TOP, INSIDE]',
|
||||||
@@ -641,7 +857,7 @@ export const render = async (
|
|||||||
try {
|
try {
|
||||||
g = await elk.layout(elkGraph);
|
g = await elk.layout(elkGraph);
|
||||||
log.debug('APA01 after - success');
|
log.debug('APA01 after - success');
|
||||||
log.debug('APA01 layout result:', JSON.stringify(g, null, 2));
|
log.info('APA01 layout result:', JSON.stringify(g, null, 2));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error('APA01 ELK layout error:', error);
|
log.error('APA01 ELK layout error:', error);
|
||||||
throw error;
|
throw error;
|
||||||
@@ -702,10 +918,10 @@ export const render = async (
|
|||||||
// sw = Math.max(bbox.width, startNode.width, startNode.labels[0].width);
|
// sw = Math.max(bbox.width, startNode.width, startNode.labels[0].width);
|
||||||
sw = Math.max(startNode.width, startNode.labels[0].width + startNode.padding);
|
sw = Math.max(startNode.width, startNode.labels[0].width + startNode.padding);
|
||||||
// sw = startNode.width;
|
// sw = startNode.width;
|
||||||
log.debug(
|
log.info(
|
||||||
'UIO width',
|
'UIO width',
|
||||||
startNode.id,
|
startNode.id,
|
||||||
startNode.with,
|
startNode.width,
|
||||||
'bbox.width=',
|
'bbox.width=',
|
||||||
bbox.width,
|
bbox.width,
|
||||||
'lw=',
|
'lw=',
|
||||||
@@ -725,7 +941,7 @@ export const render = async (
|
|||||||
log.debug(
|
log.debug(
|
||||||
'UIO width',
|
'UIO width',
|
||||||
startNode.id,
|
startNode.id,
|
||||||
startNode.with,
|
startNode.width,
|
||||||
bbox.width,
|
bbox.width,
|
||||||
'EW = ',
|
'EW = ',
|
||||||
ew,
|
ew,
|
||||||
@@ -733,38 +949,109 @@ export const render = async (
|
|||||||
startNode.innerHTML
|
startNode.innerHTML
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
startNode.x = startNode.offset.posX + startNode.width / 2;
|
||||||
|
startNode.y = startNode.offset.posY + startNode.height / 2;
|
||||||
|
endNode.x = endNode.offset.posX + endNode.width / 2;
|
||||||
|
endNode.y = endNode.offset.posY + endNode.height / 2;
|
||||||
|
|
||||||
if (startNode.calcIntersect) {
|
// Only add center points for non-subgraph nodes or when the edge path doesn't already end near the target
|
||||||
const intersection = startNode.calcIntersect(
|
const shouldAddStartCenter = startNode.shape !== 'rect33';
|
||||||
{
|
const shouldAddEndCenter = endNode.shape !== 'rect33';
|
||||||
x: startNode.offset.posX + startNode.width / 2,
|
|
||||||
y: startNode.offset.posY + startNode.height / 2,
|
if (shouldAddStartCenter) {
|
||||||
width: startNode.width,
|
edge.points.unshift({
|
||||||
height: startNode.height,
|
x: startNode.x,
|
||||||
},
|
y: startNode.y,
|
||||||
edge.points[0]
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldAddEndCenter) {
|
||||||
|
edge.points.push({
|
||||||
|
x: endNode.x,
|
||||||
|
y: endNode.y,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug and sanitize points around cutter2
|
||||||
|
const prevPoints = Array.isArray(edge.points) ? [...edge.points] : [];
|
||||||
|
const endBounds = boundsFor(endNode);
|
||||||
|
log.debug(
|
||||||
|
'PPP cutter2: Points before cutter2:',
|
||||||
|
JSON.stringify(edge.points),
|
||||||
|
'endBounds:',
|
||||||
|
endBounds,
|
||||||
|
onBorder(endBounds, edge.points[edge.points.length - 1])
|
||||||
);
|
);
|
||||||
|
// Block for reducing variable scope and guardrails for the cutter function
|
||||||
if (distance(intersection, edge.points[0]) > epsilon) {
|
|
||||||
edge.points.unshift(intersection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (endNode.calcIntersect) {
|
|
||||||
const intersection = endNode.calcIntersect(
|
|
||||||
{
|
{
|
||||||
x: endNode.offset.posX + endNode.width / 2,
|
const startBounds = boundsFor(startNode);
|
||||||
y: endNode.offset.posY + endNode.height / 2,
|
const endBounds = boundsFor(endNode);
|
||||||
width: endNode.width,
|
|
||||||
height: endNode.height,
|
const startIsGroup = !!startNode?.isGroup;
|
||||||
},
|
const endIsGroup = !!endNode?.isGroup;
|
||||||
edge.points[edge.points.length - 1]
|
|
||||||
|
const { candidate: startCandidate, centerApprox: startCenterApprox } =
|
||||||
|
getCandidateBorderPoint(prevPoints as P[], startNode, 'start');
|
||||||
|
const { candidate: endCandidate, centerApprox: endCenterApprox } =
|
||||||
|
getCandidateBorderPoint(prevPoints as P[], endNode, 'end');
|
||||||
|
|
||||||
|
const skipStart = startIsGroup && onBorder(startBounds, startCandidate);
|
||||||
|
const skipEnd = endIsGroup && onBorder(endBounds, endCandidate);
|
||||||
|
|
||||||
|
dropAutoCenterPoint(prevPoints as P[], 'start', skipStart && startCenterApprox);
|
||||||
|
dropAutoCenterPoint(prevPoints as P[], 'end', skipEnd && endCenterApprox);
|
||||||
|
|
||||||
|
if (skipStart || skipEnd) {
|
||||||
|
if (!skipStart) {
|
||||||
|
applyStartIntersectionIfNeeded(prevPoints as P[], startNode, startBounds);
|
||||||
|
}
|
||||||
|
if (!skipEnd) {
|
||||||
|
applyEndIntersectionIfNeeded(prevPoints as P[], endNode, endBounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug('PPP cutter2: skipping cutter2 due to on-border group endpoint(s)', {
|
||||||
|
skipStart,
|
||||||
|
skipEnd,
|
||||||
|
startCenterApprox,
|
||||||
|
endCenterApprox,
|
||||||
|
startCandidate,
|
||||||
|
endCandidate,
|
||||||
|
});
|
||||||
|
edge.points = prevPoints;
|
||||||
|
} else {
|
||||||
|
edge.points = cutter2(startNode, endNode, prevPoints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.debug('PPP cutter2: Points after cutter2:', JSON.stringify(edge.points));
|
||||||
|
const hasNaN = (pts: { x: number; y: number }[]) =>
|
||||||
|
pts?.some((p) => !Number.isFinite(p?.x) || !Number.isFinite(p?.y));
|
||||||
|
if (!Array.isArray(edge.points) || edge.points.length < 2 || hasNaN(edge.points)) {
|
||||||
|
log.warn(
|
||||||
|
'POI cutter2: Invalid points from cutter2, falling back to prevPoints',
|
||||||
|
edge.points
|
||||||
);
|
);
|
||||||
|
// Fallback to previous points and strip any invalid ones just in case
|
||||||
if (distance(intersection, edge.points[edge.points.length - 1]) > epsilon) {
|
const cleaned = prevPoints.filter((p) => Number.isFinite(p?.x) && Number.isFinite(p?.y));
|
||||||
edge.points.push(intersection);
|
edge.points = cleaned.length >= 2 ? cleaned : prevPoints;
|
||||||
}
|
}
|
||||||
|
log.debug('UIO cutter2: Points after cutter2 (sanitized):', edge.points);
|
||||||
|
// Remove consecutive duplicate points to avoid zero-length segments in path builders
|
||||||
|
const deduped = edge.points.filter(
|
||||||
|
(p: { x: number; y: number }, i: number, arr: { x: number; y: number }[]) => {
|
||||||
|
if (i === 0) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
const prev = arr[i - 1];
|
||||||
|
return Math.abs(p.x - prev.x) > 1e-6 || Math.abs(p.y - prev.y) > 1e-6;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (deduped.length !== edge.points.length) {
|
||||||
|
log.debug('UIO cutter2: removed consecutive duplicate points', {
|
||||||
|
before: edge.points,
|
||||||
|
after: deduped,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
edge.points = deduped;
|
||||||
const paths = insertEdge(
|
const paths = insertEdge(
|
||||||
edgesEl,
|
edgesEl,
|
||||||
edge,
|
edge,
|
||||||
@@ -772,8 +1059,10 @@ export const render = async (
|
|||||||
data4Layout.type,
|
data4Layout.type,
|
||||||
startNode,
|
startNode,
|
||||||
endNode,
|
endNode,
|
||||||
data4Layout.diagramId
|
data4Layout.diagramId,
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
log.info('APA12 edge points after insert', JSON.stringify(edge.points));
|
||||||
|
|
||||||
edge.x = edge.labels[0].x + offset.x + edge.labels[0].width / 2;
|
edge.x = edge.labels[0].x + offset.x + edge.labels[0].width / 2;
|
||||||
edge.y = edge.labels[0].y + offset.y + edge.labels[0].height / 2;
|
edge.y = edge.labels[0].y + offset.y + edge.labels[0].height / 2;
|
||||||
|
@@ -1,12 +0,0 @@
|
|||||||
# @mermaid-js/layout-tidy-tree
|
|
||||||
|
|
||||||
## 0.2.0
|
|
||||||
|
|
||||||
### Minor Changes
|
|
||||||
|
|
||||||
- [#6802](https://github.com/mermaid-js/mermaid/pull/6802) [`c8e5027`](https://github.com/mermaid-js/mermaid/commit/c8e50276e877c4de7593a09ec458c99353e65af8) Thanks [@darshanr0107](https://github.com/darshanr0107)! - feat: Update mindmap rendering to support multiple layouts, improved edge intersections, and new shapes
|
|
||||||
|
|
||||||
### Patch Changes
|
|
||||||
|
|
||||||
- Updated dependencies [[`33bc4a0`](https://github.com/mermaid-js/mermaid/commit/33bc4a0b4e2ca6d937bb0a8c4e2081b1362b2800), [`e0b45c2`](https://github.com/mermaid-js/mermaid/commit/e0b45c2d2b41c2a9038bf87646fa3ccd7560eb20), [`012530e`](https://github.com/mermaid-js/mermaid/commit/012530e98e9b8b80962ab270b6bb3b6d9f6ada05), [`c8e5027`](https://github.com/mermaid-js/mermaid/commit/c8e50276e877c4de7593a09ec458c99353e65af8)]:
|
|
||||||
- mermaid@11.11.0
|
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@mermaid-js/layout-tidy-tree",
|
"name": "@mermaid-js/layout-tidy-tree",
|
||||||
"version": "0.2.0",
|
"version": "0.1.0",
|
||||||
"description": "Tidy-tree layout engine for mermaid",
|
"description": "Tidy-tree layout engine for mermaid",
|
||||||
"module": "dist/mermaid-layout-tidy-tree.core.mjs",
|
"module": "dist/mermaid-layout-tidy-tree.core.mjs",
|
||||||
"types": "dist/layouts.d.ts",
|
"types": "dist/layouts.d.ts",
|
||||||
|
@@ -1,19 +1,5 @@
|
|||||||
# mermaid
|
# mermaid
|
||||||
|
|
||||||
## 11.11.0
|
|
||||||
|
|
||||||
### Minor Changes
|
|
||||||
|
|
||||||
- [#6704](https://github.com/mermaid-js/mermaid/pull/6704) [`012530e`](https://github.com/mermaid-js/mermaid/commit/012530e98e9b8b80962ab270b6bb3b6d9f6ada05) Thanks [@omkarht](https://github.com/omkarht)! - feat: Added support for new participant types (`actor`, `boundary`, `control`, `entity`, `database`, `collections`, `queue`) in `sequenceDiagram`.
|
|
||||||
|
|
||||||
- [#6802](https://github.com/mermaid-js/mermaid/pull/6802) [`c8e5027`](https://github.com/mermaid-js/mermaid/commit/c8e50276e877c4de7593a09ec458c99353e65af8) Thanks [@darshanr0107](https://github.com/darshanr0107)! - feat: Update mindmap rendering to support multiple layouts, improved edge intersections, and new shapes
|
|
||||||
|
|
||||||
### Patch Changes
|
|
||||||
|
|
||||||
- [#6905](https://github.com/mermaid-js/mermaid/pull/6905) [`33bc4a0`](https://github.com/mermaid-js/mermaid/commit/33bc4a0b4e2ca6d937bb0a8c4e2081b1362b2800) Thanks [@darshanr0107](https://github.com/darshanr0107)! - fix: Render newlines as spaces in class diagrams
|
|
||||||
|
|
||||||
- [#6886](https://github.com/mermaid-js/mermaid/pull/6886) [`e0b45c2`](https://github.com/mermaid-js/mermaid/commit/e0b45c2d2b41c2a9038bf87646fa3ccd7560eb20) Thanks [@darshanr0107](https://github.com/darshanr0107)! - fix: Handle arrows correctly when auto number is enabled
|
|
||||||
|
|
||||||
## 11.10.0
|
## 11.10.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mermaid",
|
"name": "mermaid",
|
||||||
"version": "11.11.0",
|
"version": "11.10.0",
|
||||||
"description": "Markdown-ish syntax for generating flowcharts, mindmaps, sequence diagrams, class diagrams, gantt charts, git graphs and more.",
|
"description": "Markdown-ish syntax for generating flowcharts, mindmaps, sequence diagrams, class diagrams, gantt charts, git graphs and more.",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"module": "./dist/mermaid.core.mjs",
|
"module": "./dist/mermaid.core.mjs",
|
||||||
@@ -82,7 +82,7 @@
|
|||||||
"katex": "^0.16.22",
|
"katex": "^0.16.22",
|
||||||
"khroma": "^2.1.0",
|
"khroma": "^2.1.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"marked": "^15.0.7",
|
"marked": "^16.0.0",
|
||||||
"roughjs": "^4.6.6",
|
"roughjs": "^4.6.6",
|
||||||
"stylis": "^4.3.6",
|
"stylis": "^4.3.6",
|
||||||
"ts-dedent": "^2.2.0",
|
"ts-dedent": "^2.2.0",
|
||||||
|
@@ -3,6 +3,7 @@ import type * as d3 from 'd3';
|
|||||||
import type { SetOptional, SetRequired } from 'type-fest';
|
import type { SetOptional, SetRequired } from 'type-fest';
|
||||||
import type { Diagram } from '../Diagram.js';
|
import type { Diagram } from '../Diagram.js';
|
||||||
import type { BaseDiagramConfig, MermaidConfig } from '../config.type.js';
|
import type { BaseDiagramConfig, MermaidConfig } from '../config.type.js';
|
||||||
|
import type { DiagramOrientation } from '../diagrams/git/gitGraphTypes.js';
|
||||||
|
|
||||||
export interface DiagramMetadata {
|
export interface DiagramMetadata {
|
||||||
title?: string;
|
title?: string;
|
||||||
@@ -35,7 +36,8 @@ export interface DiagramDB {
|
|||||||
getAccTitle?: () => string;
|
getAccTitle?: () => string;
|
||||||
setAccDescription?: (description: string) => void;
|
setAccDescription?: (description: string) => void;
|
||||||
getAccDescription?: () => string;
|
getAccDescription?: () => string;
|
||||||
|
getDirection?: () => string | undefined;
|
||||||
|
setDirection?: (dir: DiagramOrientation) => void;
|
||||||
setDisplayMode?: (title: string) => void;
|
setDisplayMode?: (title: string) => void;
|
||||||
bindFunctions?: (element: Element) => void;
|
bindFunctions?: (element: Element) => void;
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,9 @@ import { internalHelpers } from '../internals.js';
|
|||||||
import { log } from '../logger.js';
|
import { log } from '../logger.js';
|
||||||
import type { LayoutData } from './types.js';
|
import type { LayoutData } from './types.js';
|
||||||
|
|
||||||
|
// console.log('MUST be removed, this only for keeping dev server working');
|
||||||
|
// import tmp from './layout-algorithms/dagre/index.js';
|
||||||
|
|
||||||
export interface RenderOptions {
|
export interface RenderOptions {
|
||||||
algorithm?: string;
|
algorithm?: string;
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,13 @@
|
|||||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||||
import { evaluate, getUrl } from '../../diagrams/common/common.js';
|
import { evaluate } from '../../diagrams/common/common.js';
|
||||||
import { log } from '../../logger.js';
|
import { log } from '../../logger.js';
|
||||||
import { createText } from '../createText.js';
|
import { createText } from '../createText.js';
|
||||||
import utils from '../../utils.js';
|
import utils from '../../utils.js';
|
||||||
import { getLineFunctionsWithOffset } from '../../utils/lineWithOffset.js';
|
import {
|
||||||
|
getLineFunctionsWithOffset,
|
||||||
|
markerOffsets,
|
||||||
|
markerOffsets2,
|
||||||
|
} from '../../utils/lineWithOffset.js';
|
||||||
import { getSubGraphTitleMargins } from '../../utils/subGraphTitleMargins.js';
|
import { getSubGraphTitleMargins } from '../../utils/subGraphTitleMargins.js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -25,10 +29,10 @@ import {
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import createLabel from './createLabel.js';
|
import createLabel from './createLabel.js';
|
||||||
import { addEdgeMarkers } from './edgeMarker.ts';
|
import { addEdgeMarkers } from './edgeMarker.ts';
|
||||||
import { isLabelStyle } from './shapes/handDrawnShapeStyles.js';
|
import { isLabelStyle, styles2String } from './shapes/handDrawnShapeStyles.js';
|
||||||
|
|
||||||
const edgeLabels = new Map();
|
export const edgeLabels = new Map();
|
||||||
const terminalLabels = new Map();
|
export const terminalLabels = new Map();
|
||||||
|
|
||||||
export const clear = () => {
|
export const clear = () => {
|
||||||
edgeLabels.clear();
|
edgeLabels.clear();
|
||||||
@@ -43,8 +47,10 @@ export const getLabelStyles = (styleArray) => {
|
|||||||
export const insertEdgeLabel = async (elem, edge) => {
|
export const insertEdgeLabel = async (elem, edge) => {
|
||||||
let useHtmlLabels = evaluate(getConfig().flowchart.htmlLabels);
|
let useHtmlLabels = evaluate(getConfig().flowchart.htmlLabels);
|
||||||
|
|
||||||
|
const { labelStyles } = styles2String(edge);
|
||||||
|
edge.labelStyle = labelStyles;
|
||||||
const labelElement = await createText(elem, edge.label, {
|
const labelElement = await createText(elem, edge.label, {
|
||||||
style: getLabelStyles(edge.labelStyle),
|
style: edge.labelStyle,
|
||||||
useHtmlLabels,
|
useHtmlLabels,
|
||||||
addSvgBackground: true,
|
addSvgBackground: true,
|
||||||
isNode: false,
|
isNode: false,
|
||||||
@@ -55,7 +61,7 @@ export const insertEdgeLabel = async (elem, edge) => {
|
|||||||
const edgeLabel = elem.insert('g').attr('class', 'edgeLabel');
|
const edgeLabel = elem.insert('g').attr('class', 'edgeLabel');
|
||||||
|
|
||||||
// Create inner g, label, this will be positioned now for centering the text
|
// Create inner g, label, this will be positioned now for centering the text
|
||||||
const label = edgeLabel.insert('g').attr('class', 'label');
|
const label = edgeLabel.insert('g').attr('class', 'label').attr('data-id', edge.id);
|
||||||
label.node().appendChild(labelElement);
|
label.node().appendChild(labelElement);
|
||||||
|
|
||||||
// Center the label
|
// Center the label
|
||||||
@@ -438,7 +444,33 @@ const fixCorners = function (lineData) {
|
|||||||
}
|
}
|
||||||
return newLineData;
|
return newLineData;
|
||||||
};
|
};
|
||||||
export const insertEdge = function (elem, edge, clusterDb, diagramType, startNode, endNode, id) {
|
const generateDashArray = (len, oValueS, oValueE) => {
|
||||||
|
const middleLength = len - oValueS - oValueE;
|
||||||
|
const dashLength = 2; // Length of each dash
|
||||||
|
const gapLength = 2; // Length of each gap
|
||||||
|
const dashGapPairLength = dashLength + gapLength;
|
||||||
|
|
||||||
|
// Calculate number of complete dash-gap pairs that can fit
|
||||||
|
const numberOfPairs = Math.floor(middleLength / dashGapPairLength);
|
||||||
|
|
||||||
|
// Generate the middle pattern array
|
||||||
|
const middlePattern = Array(numberOfPairs).fill(`${dashLength} ${gapLength}`).join(' ');
|
||||||
|
|
||||||
|
// Combine all parts
|
||||||
|
const dashArray = `0 ${oValueS} ${middlePattern} ${oValueE}`;
|
||||||
|
|
||||||
|
return dashArray;
|
||||||
|
};
|
||||||
|
export const insertEdge = function (
|
||||||
|
elem,
|
||||||
|
edge,
|
||||||
|
clusterDb,
|
||||||
|
diagramType,
|
||||||
|
startNode,
|
||||||
|
endNode,
|
||||||
|
id,
|
||||||
|
skipIntersect = false
|
||||||
|
) {
|
||||||
const { handDrawnSeed } = getConfig();
|
const { handDrawnSeed } = getConfig();
|
||||||
let points = edge.points;
|
let points = edge.points;
|
||||||
let pointsHasChanged = false;
|
let pointsHasChanged = false;
|
||||||
@@ -452,11 +484,12 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
|
|||||||
edgeClassStyles.push(edge.cssCompiledStyles[key]);
|
edgeClassStyles.push(edge.cssCompiledStyles[key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (head.intersect && tail.intersect) {
|
log.debug('UIO intersect check', edge.points, head.x, tail.x);
|
||||||
|
if (head.intersect && tail.intersect && !skipIntersect) {
|
||||||
points = points.slice(1, edge.points.length - 1);
|
points = points.slice(1, edge.points.length - 1);
|
||||||
points.unshift(tail.intersect(points[0]));
|
points.unshift(tail.intersect(points[0]));
|
||||||
log.debug(
|
log.debug(
|
||||||
'Last point APA12',
|
'Last point UIO',
|
||||||
edge.start,
|
edge.start,
|
||||||
'-->',
|
'-->',
|
||||||
edge.end,
|
edge.end,
|
||||||
@@ -466,6 +499,7 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
|
|||||||
);
|
);
|
||||||
points.push(head.intersect(points[points.length - 1]));
|
points.push(head.intersect(points[points.length - 1]));
|
||||||
}
|
}
|
||||||
|
const pointsStr = btoa(JSON.stringify(points));
|
||||||
if (edge.toCluster) {
|
if (edge.toCluster) {
|
||||||
log.info('to cluster abc88', clusterDb.get(edge.toCluster));
|
log.info('to cluster abc88', clusterDb.get(edge.toCluster));
|
||||||
points = cutPathAtIntersect(edge.points, clusterDb.get(edge.toCluster).node);
|
points = cutPathAtIntersect(edge.points, clusterDb.get(edge.toCluster).node);
|
||||||
@@ -529,6 +563,10 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
|
|||||||
curve = curveBasis;
|
curve = curveBasis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if (edge.curve) {
|
||||||
|
// curve = edge.curve;
|
||||||
|
// }
|
||||||
|
|
||||||
const { x, y } = getLineFunctionsWithOffset(edge);
|
const { x, y } = getLineFunctionsWithOffset(edge);
|
||||||
const lineFunction = line().x(x).y(y).curve(curve);
|
const lineFunction = line().x(x).y(y).curve(curve);
|
||||||
|
|
||||||
@@ -560,10 +598,14 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
|
|||||||
strokeClasses += ' edge-pattern-solid';
|
strokeClasses += ' edge-pattern-solid';
|
||||||
}
|
}
|
||||||
let svgPath;
|
let svgPath;
|
||||||
let linePath = lineFunction(lineData);
|
let linePath =
|
||||||
const edgeStyles = Array.isArray(edge.style) ? edge.style : edge.style ? [edge.style] : [];
|
edge.curve === 'rounded'
|
||||||
|
? generateRoundedPath(applyMarkerOffsetsToPoints(lineData, edge), 5)
|
||||||
|
: lineFunction(lineData);
|
||||||
|
const edgeStyles = Array.isArray(edge.style) ? edge.style : [edge.style];
|
||||||
let strokeColor = edgeStyles.find((style) => style?.startsWith('stroke:'));
|
let strokeColor = edgeStyles.find((style) => style?.startsWith('stroke:'));
|
||||||
|
|
||||||
|
let animatedEdge = false;
|
||||||
if (edge.look === 'handDrawn') {
|
if (edge.look === 'handDrawn') {
|
||||||
const rc = rough.svg(elem);
|
const rc = rough.svg(elem);
|
||||||
Object.assign([], lineData);
|
Object.assign([], lineData);
|
||||||
@@ -594,7 +636,10 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
|
|||||||
animationClass = ' edge-animation-' + edge.animation;
|
animationClass = ' edge-animation-' + edge.animation;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pathStyle = stylesFromClasses ? stylesFromClasses + ';' + styles + ';' : styles;
|
const pathStyle =
|
||||||
|
(stylesFromClasses ? stylesFromClasses + ';' + styles + ';' : styles) +
|
||||||
|
';' +
|
||||||
|
(edgeStyles ? edgeStyles.reduce((acc, style) => acc + ';' + style, '') : '');
|
||||||
svgPath = elem
|
svgPath = elem
|
||||||
.append('path')
|
.append('path')
|
||||||
.attr('d', linePath)
|
.attr('d', linePath)
|
||||||
@@ -604,11 +649,39 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
|
|||||||
' ' + strokeClasses + (edge.classes ? ' ' + edge.classes : '') + (animationClass ?? '')
|
' ' + strokeClasses + (edge.classes ? ' ' + edge.classes : '') + (animationClass ?? '')
|
||||||
)
|
)
|
||||||
.attr('style', pathStyle);
|
.attr('style', pathStyle);
|
||||||
|
|
||||||
|
//eslint-disable-next-line @typescript-eslint/prefer-regexp-exec
|
||||||
strokeColor = pathStyle.match(/stroke:([^;]+)/)?.[1];
|
strokeColor = pathStyle.match(/stroke:([^;]+)/)?.[1];
|
||||||
|
|
||||||
|
// Possible fix to remove eslint-disable-next-line
|
||||||
|
//strokeColor = /stroke:([^;]+)/.exec(pathStyle)?.[1];
|
||||||
|
|
||||||
|
animatedEdge =
|
||||||
|
edge.animate === true || !!edge.animation || stylesFromClasses.includes('animation');
|
||||||
|
const pathNode = svgPath.node();
|
||||||
|
const len = typeof pathNode.getTotalLength === 'function' ? pathNode.getTotalLength() : 0;
|
||||||
|
const oValueS = markerOffsets2[edge.arrowTypeStart] || 0;
|
||||||
|
const oValueE = markerOffsets2[edge.arrowTypeEnd] || 0;
|
||||||
|
|
||||||
|
if (edge.look === 'neo' && !animatedEdge) {
|
||||||
|
const dashArray =
|
||||||
|
edge.pattern === 'dotted' || edge.pattern === 'dashed'
|
||||||
|
? generateDashArray(len, oValueS, oValueE)
|
||||||
|
: `0 ${oValueS} ${len - oValueS - oValueE} ${oValueE}`;
|
||||||
|
|
||||||
|
// No offset needed because we already start with a zero-length dash that effectively sets us up for a gap at the start.
|
||||||
|
const mOffset = `stroke-dasharray: ${dashArray}; stroke-dashoffset: 0;`;
|
||||||
|
svgPath.attr('style', mOffset + svgPath.attr('style'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEBUG code, DO NOT REMOVE
|
// MC Special
|
||||||
// adds a red circle at each edge coordinate
|
svgPath.attr('data-edge', true);
|
||||||
|
svgPath.attr('data-et', 'edge');
|
||||||
|
svgPath.attr('data-id', edge.id);
|
||||||
|
svgPath.attr('data-points', pointsStr);
|
||||||
|
|
||||||
|
// DEBUG code, adds a red circle at each edge coordinate
|
||||||
// cornerPoints.forEach((point) => {
|
// cornerPoints.forEach((point) => {
|
||||||
// elem
|
// elem
|
||||||
// .append('circle')
|
// .append('circle')
|
||||||
@@ -618,19 +691,27 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
|
|||||||
// .attr('cx', point.x)
|
// .attr('cx', point.x)
|
||||||
// .attr('cy', point.y);
|
// .attr('cy', point.y);
|
||||||
// });
|
// });
|
||||||
// lineData.forEach((point) => {
|
if (edge.showPoints) {
|
||||||
// elem
|
lineData.forEach((point) => {
|
||||||
// .append('circle')
|
elem
|
||||||
// .style('stroke', 'red')
|
.append('circle')
|
||||||
// .style('fill', 'red')
|
.style('stroke', 'red')
|
||||||
// .attr('r', 1)
|
.style('fill', 'red')
|
||||||
// .attr('cx', point.x)
|
.attr('r', 1)
|
||||||
// .attr('cy', point.y);
|
.attr('cx', point.x)
|
||||||
// });
|
.attr('cy', point.y);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let url = '';
|
let url = '';
|
||||||
if (getConfig().flowchart.arrowMarkerAbsolute || getConfig().state.arrowMarkerAbsolute) {
|
if (getConfig().flowchart.arrowMarkerAbsolute || getConfig().state.arrowMarkerAbsolute) {
|
||||||
url = getUrl(true);
|
url =
|
||||||
|
window.location.protocol +
|
||||||
|
'//' +
|
||||||
|
window.location.host +
|
||||||
|
window.location.pathname +
|
||||||
|
window.location.search;
|
||||||
|
url = url.replace(/\(/g, '\\(').replace(/\)/g, '\\)');
|
||||||
}
|
}
|
||||||
log.info('arrowTypeStart', edge.arrowTypeStart);
|
log.info('arrowTypeStart', edge.arrowTypeStart);
|
||||||
log.info('arrowTypeEnd', edge.arrowTypeEnd);
|
log.info('arrowTypeEnd', edge.arrowTypeEnd);
|
||||||
@@ -649,3 +730,134 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
|
|||||||
paths.originalPath = edge.points;
|
paths.originalPath = edge.points;
|
||||||
return paths;
|
return paths;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates SVG path data with rounded corners from an array of points.
|
||||||
|
* @param {Array} points - Array of points in the format [{x: Number, y: Number}, ...]
|
||||||
|
* @param {Number} radius - The radius of the rounded corners
|
||||||
|
* @returns {String} - SVG path data string
|
||||||
|
*/
|
||||||
|
function generateRoundedPath(points, radius) {
|
||||||
|
if (points.length < 2) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = '';
|
||||||
|
const size = points.length;
|
||||||
|
const epsilon = 1e-5;
|
||||||
|
|
||||||
|
for (let i = 0; i < size; i++) {
|
||||||
|
const currPoint = points[i];
|
||||||
|
const prevPoint = points[i - 1];
|
||||||
|
const nextPoint = points[i + 1];
|
||||||
|
|
||||||
|
if (i === 0) {
|
||||||
|
// Move to the first point
|
||||||
|
path += `M${currPoint.x},${currPoint.y}`;
|
||||||
|
} else if (i === size - 1) {
|
||||||
|
// Last point, draw a straight line to the final point
|
||||||
|
path += `L${currPoint.x},${currPoint.y}`;
|
||||||
|
} else {
|
||||||
|
// Calculate vectors for incoming and outgoing segments
|
||||||
|
const dx1 = currPoint.x - prevPoint.x;
|
||||||
|
const dy1 = currPoint.y - prevPoint.y;
|
||||||
|
const dx2 = nextPoint.x - currPoint.x;
|
||||||
|
const dy2 = nextPoint.y - currPoint.y;
|
||||||
|
|
||||||
|
const len1 = Math.hypot(dx1, dy1);
|
||||||
|
const len2 = Math.hypot(dx2, dy2);
|
||||||
|
|
||||||
|
// Prevent division by zero
|
||||||
|
if (len1 < epsilon || len2 < epsilon) {
|
||||||
|
path += `L${currPoint.x},${currPoint.y}`;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize the vectors
|
||||||
|
const nx1 = dx1 / len1;
|
||||||
|
const ny1 = dy1 / len1;
|
||||||
|
const nx2 = dx2 / len2;
|
||||||
|
const ny2 = dy2 / len2;
|
||||||
|
|
||||||
|
// Calculate the angle between the vectors
|
||||||
|
const dot = nx1 * nx2 + ny1 * ny2;
|
||||||
|
// Clamp the dot product to avoid numerical issues with acos
|
||||||
|
const clampedDot = Math.max(-1, Math.min(1, dot));
|
||||||
|
const angle = Math.acos(clampedDot);
|
||||||
|
|
||||||
|
// Skip rounding if the angle is too small or too close to 180 degrees
|
||||||
|
if (angle < epsilon || Math.abs(Math.PI - angle) < epsilon) {
|
||||||
|
path += `L${currPoint.x},${currPoint.y}`;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the distance to offset the control point
|
||||||
|
const cutLen = Math.min(radius / Math.sin(angle / 2), len1 / 2, len2 / 2);
|
||||||
|
|
||||||
|
// Calculate the start and end points of the curve
|
||||||
|
const startX = currPoint.x - nx1 * cutLen;
|
||||||
|
const startY = currPoint.y - ny1 * cutLen;
|
||||||
|
const endX = currPoint.x + nx2 * cutLen;
|
||||||
|
const endY = currPoint.y + ny2 * cutLen;
|
||||||
|
|
||||||
|
// Draw the line to the start of the curve
|
||||||
|
path += `L${startX},${startY}`;
|
||||||
|
|
||||||
|
// Draw the quadratic Bezier curve
|
||||||
|
path += `Q${currPoint.x},${currPoint.y} ${endX},${endY}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
// Helper function to calculate delta and angle between two points
|
||||||
|
function calculateDeltaAndAngle(point1, point2) {
|
||||||
|
if (!point1 || !point2) {
|
||||||
|
return { angle: 0, deltaX: 0, deltaY: 0 };
|
||||||
|
}
|
||||||
|
const deltaX = point2.x - point1.x;
|
||||||
|
const deltaY = point2.y - point1.y;
|
||||||
|
const angle = Math.atan2(deltaY, deltaX);
|
||||||
|
return { angle, deltaX, deltaY };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to adjust the first and last points of the points array
|
||||||
|
function applyMarkerOffsetsToPoints(points, edge) {
|
||||||
|
// Copy the points array to avoid mutating the original data
|
||||||
|
const newPoints = points.map((point) => ({ ...point }));
|
||||||
|
|
||||||
|
// Handle the first point (start of the edge)
|
||||||
|
if (points.length >= 2 && markerOffsets[edge.arrowTypeStart]) {
|
||||||
|
const offsetValue = markerOffsets[edge.arrowTypeStart];
|
||||||
|
|
||||||
|
const point1 = points[0];
|
||||||
|
const point2 = points[1];
|
||||||
|
|
||||||
|
const { angle } = calculateDeltaAndAngle(point1, point2);
|
||||||
|
|
||||||
|
const offsetX = offsetValue * Math.cos(angle);
|
||||||
|
const offsetY = offsetValue * Math.sin(angle);
|
||||||
|
|
||||||
|
newPoints[0].x = point1.x + offsetX;
|
||||||
|
newPoints[0].y = point1.y + offsetY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the last point (end of the edge)
|
||||||
|
const n = points.length;
|
||||||
|
if (n >= 2 && markerOffsets[edge.arrowTypeEnd]) {
|
||||||
|
const offsetValue = markerOffsets[edge.arrowTypeEnd];
|
||||||
|
|
||||||
|
const point1 = points[n - 1];
|
||||||
|
const point2 = points[n - 2];
|
||||||
|
|
||||||
|
const { angle } = calculateDeltaAndAngle(point2, point1);
|
||||||
|
|
||||||
|
const offsetX = offsetValue * Math.cos(angle);
|
||||||
|
const offsetY = offsetValue * Math.sin(angle);
|
||||||
|
|
||||||
|
newPoints[n - 1].x = point1.x - offsetX;
|
||||||
|
newPoints[n - 1].y = point1.y - offsetY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return newPoints;
|
||||||
|
}
|
||||||
|
@@ -20,7 +20,11 @@ export const compileStyles = (node: Node) => {
|
|||||||
// the array is the styles of node from the classes it is using
|
// the array is the styles of node from the classes it is using
|
||||||
// node.cssStyles is an array of styles directly set on the node
|
// node.cssStyles is an array of styles directly set on the node
|
||||||
// concat the arrays and remove duplicates such that the values from node.cssStyles are used if there are duplicates
|
// concat the arrays and remove duplicates such that the values from node.cssStyles are used if there are duplicates
|
||||||
const stylesMap = styles2Map([...(node.cssCompiledStyles || []), ...(node.cssStyles || [])]);
|
const stylesMap = styles2Map([
|
||||||
|
...(node.cssCompiledStyles || []),
|
||||||
|
...(node.cssStyles || []),
|
||||||
|
...(node.labelStyle || []),
|
||||||
|
]);
|
||||||
return { stylesMap, stylesArray: [...stylesMap] };
|
return { stylesMap, stylesArray: [...stylesMap] };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -4,12 +4,22 @@ import type { EdgeData, Point } from '../types.js';
|
|||||||
// under any transparent markers.
|
// under any transparent markers.
|
||||||
// The offsets are calculated from the markers' dimensions.
|
// The offsets are calculated from the markers' dimensions.
|
||||||
export const markerOffsets = {
|
export const markerOffsets = {
|
||||||
aggregation: 18,
|
aggregation: 17.25,
|
||||||
extension: 18,
|
extension: 17.25,
|
||||||
composition: 18,
|
composition: 17.25,
|
||||||
dependency: 6,
|
dependency: 6,
|
||||||
lollipop: 13.5,
|
lollipop: 13.5,
|
||||||
arrow_point: 4,
|
arrow_point: 4,
|
||||||
|
//arrow_cross: 24,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
// We need to draw the lines a bit shorter to avoid drawing
|
||||||
|
// under any transparent markers.
|
||||||
|
// The offsets are calculated from the markers' dimensions.
|
||||||
|
export const markerOffsets2 = {
|
||||||
|
arrow_point: 9,
|
||||||
|
arrow_cross: 12.5,
|
||||||
|
arrow_circle: 12.5,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -104,6 +114,7 @@ export const getLineFunctionsWithOffset = (
|
|||||||
adjustment *= DIRECTION === 'right' ? -1 : 1;
|
adjustment *= DIRECTION === 'right' ? -1 : 1;
|
||||||
offset += adjustment;
|
offset += adjustment;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pointTransformer(d).x + offset;
|
return pointTransformer(d).x + offset;
|
||||||
},
|
},
|
||||||
y: function (
|
y: function (
|
||||||
|
@@ -1,19 +1,5 @@
|
|||||||
# mermaid
|
# mermaid
|
||||||
|
|
||||||
## 11.11.0
|
|
||||||
|
|
||||||
### Minor Changes
|
|
||||||
|
|
||||||
- [#6704](https://github.com/mermaid-js/mermaid/pull/6704) [`012530e`](https://github.com/mermaid-js/mermaid/commit/012530e98e9b8b80962ab270b6bb3b6d9f6ada05) Thanks [@omkarht](https://github.com/omkarht)! - feat: Added support for new participant types (`actor`, `boundary`, `control`, `entity`, `database`, `collections`, `queue`) in `sequenceDiagram`.
|
|
||||||
|
|
||||||
- [#6802](https://github.com/mermaid-js/mermaid/pull/6802) [`c8e5027`](https://github.com/mermaid-js/mermaid/commit/c8e50276e877c4de7593a09ec458c99353e65af8) Thanks [@darshanr0107](https://github.com/darshanr0107)! - feat: Update mindmap rendering to support multiple layouts, improved edge intersections, and new shapes
|
|
||||||
|
|
||||||
### Patch Changes
|
|
||||||
|
|
||||||
- [#6905](https://github.com/mermaid-js/mermaid/pull/6905) [`33bc4a0`](https://github.com/mermaid-js/mermaid/commit/33bc4a0b4e2ca6d937bb0a8c4e2081b1362b2800) Thanks [@darshanr0107](https://github.com/darshanr0107)! - fix: Render newlines as spaces in class diagrams
|
|
||||||
|
|
||||||
- [#6886](https://github.com/mermaid-js/mermaid/pull/6886) [`e0b45c2`](https://github.com/mermaid-js/mermaid/commit/e0b45c2d2b41c2a9038bf87646fa3ccd7560eb20) Thanks [@darshanr0107](https://github.com/darshanr0107)! - fix: Handle arrows correctly when auto number is enabled
|
|
||||||
|
|
||||||
## 11.10.0
|
## 11.10.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@mermaid-js/tiny",
|
"name": "@mermaid-js/tiny",
|
||||||
"version": "11.11.0",
|
"version": "11.10.0",
|
||||||
"description": "Tiny version of mermaid",
|
"description": "Tiny version of mermaid",
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"main": "./dist/mermaid.tiny.js",
|
"main": "./dist/mermaid.tiny.js",
|
||||||
|
81
pnpm-lock.yaml
generated
81
pnpm-lock.yaml
generated
@@ -269,8 +269,8 @@ importers:
|
|||||||
specifier: ^4.17.21
|
specifier: ^4.17.21
|
||||||
version: 4.17.21
|
version: 4.17.21
|
||||||
marked:
|
marked:
|
||||||
specifier: ^15.0.7
|
specifier: ^16.0.0
|
||||||
version: 15.0.12
|
version: 16.2.1
|
||||||
roughjs:
|
roughjs:
|
||||||
specifier: ^4.6.6
|
specifier: ^4.6.6
|
||||||
version: 4.6.6(patch_hash=3543d47108cb41b68ec6a671c0e1f9d0cfe2ce524fea5b0992511ae84c3c6b64)
|
version: 4.6.6(patch_hash=3543d47108cb41b68ec6a671c0e1f9d0cfe2ce524fea5b0992511ae84c3c6b64)
|
||||||
@@ -7445,9 +7445,9 @@ packages:
|
|||||||
markdown-table@3.0.4:
|
markdown-table@3.0.4:
|
||||||
resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
|
resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
|
||||||
|
|
||||||
marked@15.0.12:
|
marked@16.2.1:
|
||||||
resolution: {integrity: sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==}
|
resolution: {integrity: sha512-r3UrXED9lMlHF97jJByry90cwrZBBvZmjG1L68oYfuPMW+uDTnuMbyJDymCWwbTE+f+3LhpNDKfpR3a3saFyjA==}
|
||||||
engines: {node: '>= 18'}
|
engines: {node: '>= 20'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
marked@4.3.0:
|
marked@4.3.0:
|
||||||
@@ -14430,14 +14430,6 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 6.1.1(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0)
|
vite: 6.1.1(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0)
|
||||||
|
|
||||||
'@unocss/astro@66.4.2(vite@6.1.6(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0))':
|
|
||||||
dependencies:
|
|
||||||
'@unocss/core': 66.4.2
|
|
||||||
'@unocss/reset': 66.4.2
|
|
||||||
'@unocss/vite': 66.4.2(vite@6.1.6(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0))
|
|
||||||
optionalDependencies:
|
|
||||||
vite: 6.1.6(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0)
|
|
||||||
|
|
||||||
'@unocss/cli@66.4.2':
|
'@unocss/cli@66.4.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ampproject/remapping': 2.3.0
|
'@ampproject/remapping': 2.3.0
|
||||||
@@ -14582,19 +14574,6 @@ snapshots:
|
|||||||
unplugin-utils: 0.2.4
|
unplugin-utils: 0.2.4
|
||||||
vite: 6.1.1(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0)
|
vite: 6.1.1(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0)
|
||||||
|
|
||||||
'@unocss/vite@66.4.2(vite@6.1.6(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0))':
|
|
||||||
dependencies:
|
|
||||||
'@ampproject/remapping': 2.3.0
|
|
||||||
'@unocss/config': 66.4.2
|
|
||||||
'@unocss/core': 66.4.2
|
|
||||||
'@unocss/inspector': 66.4.2
|
|
||||||
chokidar: 3.6.0
|
|
||||||
magic-string: 0.30.17
|
|
||||||
pathe: 2.0.3
|
|
||||||
tinyglobby: 0.2.14
|
|
||||||
unplugin-utils: 0.2.4
|
|
||||||
vite: 6.1.6(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0)
|
|
||||||
|
|
||||||
'@unrs/resolver-binding-android-arm-eabi@1.11.1':
|
'@unrs/resolver-binding-android-arm-eabi@1.11.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -14658,10 +14637,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
vite-plugin-pwa: 1.0.0(vite@6.1.1(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.3.0)
|
vite-plugin-pwa: 1.0.0(vite@6.1.1(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.3.0)
|
||||||
|
|
||||||
'@vite-pwa/vitepress@1.0.0(vite-plugin-pwa@1.0.0(vite@6.1.6(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.3.0))':
|
|
||||||
dependencies:
|
|
||||||
vite-plugin-pwa: 1.0.0(vite@6.1.6(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.3.0)
|
|
||||||
|
|
||||||
'@vitejs/plugin-vue@5.2.1(vite@5.4.19(@types/node@22.13.5)(terser@5.39.0))(vue@3.5.13(typescript@5.7.3))':
|
'@vitejs/plugin-vue@5.2.1(vite@5.4.19(@types/node@22.13.5)(terser@5.39.0))(vue@3.5.13(typescript@5.7.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
vite: 5.4.19(@types/node@22.13.5)(terser@5.39.0)
|
vite: 5.4.19(@types/node@22.13.5)(terser@5.39.0)
|
||||||
@@ -14673,12 +14648,6 @@ snapshots:
|
|||||||
vite: 6.1.1(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0)
|
vite: 6.1.1(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0)
|
||||||
vue: 3.5.13(typescript@5.7.3)
|
vue: 3.5.13(typescript@5.7.3)
|
||||||
|
|
||||||
'@vitejs/plugin-vue@6.0.0(vite@6.1.6(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0))(vue@3.5.13(typescript@5.7.3))':
|
|
||||||
dependencies:
|
|
||||||
'@rolldown/pluginutils': 1.0.0-beta.19
|
|
||||||
vite: 6.1.6(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0)
|
|
||||||
vue: 3.5.13(typescript@5.7.3)
|
|
||||||
|
|
||||||
'@vitest/coverage-v8@3.0.6(vitest@3.0.6)':
|
'@vitest/coverage-v8@3.0.6(vitest@3.0.6)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ampproject/remapping': 2.3.0
|
'@ampproject/remapping': 2.3.0
|
||||||
@@ -19176,7 +19145,7 @@ snapshots:
|
|||||||
|
|
||||||
markdown-table@3.0.4: {}
|
markdown-table@3.0.4: {}
|
||||||
|
|
||||||
marked@15.0.12: {}
|
marked@16.2.1: {}
|
||||||
|
|
||||||
marked@4.3.0: {}
|
marked@4.3.0: {}
|
||||||
|
|
||||||
@@ -21843,33 +21812,6 @@ snapshots:
|
|||||||
- postcss
|
- postcss
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
unocss@66.4.2(postcss@8.5.6)(vite@6.1.6(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0)):
|
|
||||||
dependencies:
|
|
||||||
'@unocss/astro': 66.4.2(vite@6.1.6(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0))
|
|
||||||
'@unocss/cli': 66.4.2
|
|
||||||
'@unocss/core': 66.4.2
|
|
||||||
'@unocss/postcss': 66.4.2(postcss@8.5.6)
|
|
||||||
'@unocss/preset-attributify': 66.4.2
|
|
||||||
'@unocss/preset-icons': 66.4.2
|
|
||||||
'@unocss/preset-mini': 66.4.2
|
|
||||||
'@unocss/preset-tagify': 66.4.2
|
|
||||||
'@unocss/preset-typography': 66.4.2
|
|
||||||
'@unocss/preset-uno': 66.4.2
|
|
||||||
'@unocss/preset-web-fonts': 66.4.2
|
|
||||||
'@unocss/preset-wind': 66.4.2
|
|
||||||
'@unocss/preset-wind3': 66.4.2
|
|
||||||
'@unocss/preset-wind4': 66.4.2
|
|
||||||
'@unocss/transformer-attributify-jsx': 66.4.2
|
|
||||||
'@unocss/transformer-compile-class': 66.4.2
|
|
||||||
'@unocss/transformer-directives': 66.4.2
|
|
||||||
'@unocss/transformer-variant-group': 66.4.2
|
|
||||||
'@unocss/vite': 66.4.2(vite@6.1.6(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0))
|
|
||||||
optionalDependencies:
|
|
||||||
vite: 6.1.6(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0)
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- postcss
|
|
||||||
- supports-color
|
|
||||||
|
|
||||||
unpipe@1.0.0: {}
|
unpipe@1.0.0: {}
|
||||||
|
|
||||||
unplugin-utils@0.2.4:
|
unplugin-utils@0.2.4:
|
||||||
@@ -22024,17 +21966,6 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
vite-plugin-pwa@1.0.0(vite@6.1.6(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.3.0):
|
|
||||||
dependencies:
|
|
||||||
debug: 4.4.0
|
|
||||||
pretty-bytes: 6.1.1
|
|
||||||
tinyglobby: 0.2.12
|
|
||||||
vite: 6.1.6(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0)
|
|
||||||
workbox-build: 7.1.1(@types/babel__core@7.20.5)
|
|
||||||
workbox-window: 7.3.0
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
|
|
||||||
vite@5.4.19(@types/node@22.13.5)(terser@5.39.0):
|
vite@5.4.19(@types/node@22.13.5)(terser@5.39.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.21.5
|
esbuild: 0.21.5
|
||||||
|
Reference in New Issue
Block a user