mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-08-15 14:29:25 +02:00
5432 WIP, parsing works
This commit is contained in:
@@ -83,349 +83,16 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="flex">
|
|
||||||
<pre id="diagram" class="mermaid2">
|
|
||||||
---
|
|
||||||
title: hello2
|
|
||||||
config:
|
|
||||||
look: handDrawn
|
|
||||||
layout: elk
|
|
||||||
elk:
|
|
||||||
<!-- nodePlacementStrategy: INTERACTIVE -->
|
|
||||||
<!-- mergeEdges: true -->
|
|
||||||
---
|
|
||||||
stateDiagram-v2
|
|
||||||
direction LR
|
|
||||||
accTitle: An idealized Open Source supply-chain graph
|
|
||||||
|
|
||||||
%%
|
|
||||||
state "🟦 Importer" as author_importer
|
|
||||||
state "🟥 Supplier, Owner" as author_owner
|
|
||||||
state "🟨🟥 Maintainer, Author\n🟨 Custodian" as author
|
|
||||||
state "🟩 Distributor" as repository_distributor
|
|
||||||
state "🟦 Importer" as language_importer
|
|
||||||
state "🟦🟨 Packager" as language_packager
|
|
||||||
state "🟦🟨 OSS Steward" as language_steward
|
|
||||||
state "🟨 Curator" as language_curator
|
|
||||||
state "🟩 Distributor" as language_distributor
|
|
||||||
state "🟦 Contributor" as contributor
|
|
||||||
state "🟦 Importer" as package_importer
|
|
||||||
state "🟨 Patcher" as package_patcher
|
|
||||||
state "🟨🟦 Builder\n🟨🟦 Packager\n🟨🟦 Containerizer" as package_packager
|
|
||||||
state "🟨 Curator" as package_curator
|
|
||||||
state "🟩 Distributor" as package_distributor
|
|
||||||
state "🟦 Importer" as integrator_importer
|
|
||||||
state "🟥 Supplier, Manufacturer, Owner" as integrator_owner
|
|
||||||
state "🟦🟨🟥 Integrator, Developer" as integrator_developer
|
|
||||||
state "🟩🟨 SBOM Redactor\n🟩 Publisher" as integrator_publisher
|
|
||||||
state "🟦🟨 Builder" as integrator_builder
|
|
||||||
state "🟨 Deployer" as deployer
|
|
||||||
state "🟦 Vuln. Checker" as integrator_checker
|
|
||||||
state "🟩🟨 SBOM Redactor" as redactor
|
|
||||||
state "🟦 Consumer\n🟦 User" as consumer
|
|
||||||
state "🟦 Auditor" as auditor_internal
|
|
||||||
state "🟦 Auditor" as auditor_external
|
|
||||||
|
|
||||||
%%
|
|
||||||
classDef createsSBOM stroke:red,stroke-width:3px;
|
|
||||||
classDef updatesSBOM stroke:yellow,stroke-width:3px;
|
|
||||||
classDef assemblesSBOM stroke:yellow,stroke-width:3px;
|
|
||||||
classDef distributesSBOM stroke:green,stroke-width:3px;
|
|
||||||
classDef verifiesSBOM stroke:#07f,stroke-width:3px;
|
|
||||||
|
|
||||||
%%
|
|
||||||
class author_importer verifiesSBOM
|
|
||||||
class author_owner createsSBOM
|
|
||||||
class manufacturer_owner createsSBOM
|
|
||||||
class author assemblesSBOM
|
|
||||||
class package_importer verifiesSBOM
|
|
||||||
class package_patcher updatesSBOM
|
|
||||||
class package_packager assemblesSBOM
|
|
||||||
class package_curator distributesSBOM
|
|
||||||
class package_distributor distributesSBOM
|
|
||||||
class language_importer verifiesSBOM
|
|
||||||
class language_packager assemblesSBOM
|
|
||||||
class language_steward updatesSBOM
|
|
||||||
class language_curator distributesSBOM
|
|
||||||
class language_distributor distributesSBOM
|
|
||||||
class repository_distributor distributesSBOM
|
|
||||||
class integrator_importer verifiesSBOM
|
|
||||||
class integrator_owner createsSBOM
|
|
||||||
class integrator_developer assemblesSBOM
|
|
||||||
class integrator_publisher distributesSBOM
|
|
||||||
class integrator_builder assemblesSBOM
|
|
||||||
class integrator_checker verifiesSBOM
|
|
||||||
class deployer assemblesSBOM
|
|
||||||
class redactor distributesSBOM
|
|
||||||
class auditor_internal verifiesSBOM
|
|
||||||
class auditor_external verifiesSBOM
|
|
||||||
|
|
||||||
state "Maintainer Environment" as environment_maintainer {
|
|
||||||
[*] --> author_importer
|
|
||||||
[*] --> author
|
|
||||||
author_importer --> author
|
|
||||||
author_owner --> author
|
|
||||||
author --> language_packager
|
|
||||||
}
|
|
||||||
|
|
||||||
[*] --> environment_maintainer
|
|
||||||
|
|
||||||
state "Language Ecosystem" as ecosystem_lang {
|
|
||||||
[*] --> language_importer
|
|
||||||
[*] --> language_steward
|
|
||||||
[*] --> language_curator
|
|
||||||
[*] --> language_distributor
|
|
||||||
language_importer --> language_distributor
|
|
||||||
language_importer --> language_curator
|
|
||||||
language_steward --> language_curator
|
|
||||||
language_curator --> language_distributor
|
|
||||||
}
|
|
||||||
|
|
||||||
language_packager --> ecosystem_lang
|
|
||||||
ecosystem_lang --> ecosystem_lang
|
|
||||||
|
|
||||||
state "Public Collaboration Ecosystem" as ecosystem_repo {
|
|
||||||
[*] --> repository_distributor
|
|
||||||
}
|
|
||||||
|
|
||||||
author --> ecosystem_repo
|
|
||||||
ecosystem_repo --> author
|
|
||||||
|
|
||||||
repository_distributor --> contributor
|
|
||||||
contributor --> repository_distributor
|
|
||||||
|
|
||||||
state "Package Ecosystem" as ecosystem_package {
|
|
||||||
[*] --> package_importer
|
|
||||||
[*] --> package_packager
|
|
||||||
[*] --> package_patcher
|
|
||||||
package_importer --> package_patcher
|
|
||||||
package_importer --> package_packager
|
|
||||||
package_patcher --> package_packager
|
|
||||||
package_packager --> package_curator
|
|
||||||
package_packager --> package_distributor
|
|
||||||
package_curator --> package_distributor
|
|
||||||
}
|
|
||||||
|
|
||||||
repository_distributor --> ecosystem_package
|
|
||||||
language_distributor --> ecosystem_package
|
|
||||||
ecosystem_package --> ecosystem_package
|
|
||||||
|
|
||||||
state "Integrator Environment" as environment_integrator {
|
|
||||||
[*] --> integrator_developer
|
|
||||||
[*] --> integrator_importer
|
|
||||||
integrator_importer --> integrator_developer
|
|
||||||
integrator_owner --> integrator_developer
|
|
||||||
integrator_builder --> integrator_publisher
|
|
||||||
integrator_developer --> integrator_checker
|
|
||||||
integrator_checker --> integrator_developer
|
|
||||||
auditor_internal --> integrator_developer
|
|
||||||
integrator_developer --> integrator_builder
|
|
||||||
integrator_developer --> auditor_internal
|
|
||||||
}
|
|
||||||
|
|
||||||
repository_distributor --> environment_integrator
|
|
||||||
language_distributor --> environment_integrator
|
|
||||||
package_distributor --> environment_integrator
|
|
||||||
|
|
||||||
state "Production Environment" as environment_prod {
|
|
||||||
[*] --> deployer
|
|
||||||
deployer --> redactor
|
|
||||||
}
|
|
||||||
|
|
||||||
integrator_publisher --> [*]
|
|
||||||
integrator_developer --> environment_prod
|
|
||||||
integrator_builder --> environment_prod
|
|
||||||
integrator_publisher --> environment_prod
|
|
||||||
|
|
||||||
deployer --> auditor_external
|
|
||||||
deployer --> consumer
|
|
||||||
redactor --> consumer
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<pre id="diagram" class="mermaid2">
|
|
||||||
---
|
|
||||||
config:
|
|
||||||
look: neo
|
|
||||||
---
|
|
||||||
flowchart RL
|
|
||||||
subgraph " "
|
|
||||||
A5@{ shape: manual-file, label: "a label"}
|
|
||||||
B5@{ shape: manual-input, label: "a label" }
|
|
||||||
C5@{ shape: mul-doc, label: "a label" }
|
|
||||||
D5@{ shape: mul-proc, label: "a label" }
|
|
||||||
E5@{ shape: paper-tape, label: "a label" }
|
|
||||||
B3@{ shape: das, label: "a label" }
|
|
||||||
C3@{ shape: disk, label: "a label" }
|
|
||||||
D4@{ shape: lin-doc, label: "a label" }
|
|
||||||
E4@{ shape: loop-limit, label: "a label" }
|
|
||||||
end
|
|
||||||
subgraph " "
|
|
||||||
B6@{ shape: summary, label: "a label" }
|
|
||||||
C6@{ shape: tag-we-rect, label: "a label" }
|
|
||||||
D6@{ shape: tag-rect, label: "a label" }
|
|
||||||
A2@{ shape: fork}
|
|
||||||
B2@{ shape: hourglass }
|
|
||||||
C2@{ shape: comment, label: "I am a comment" }
|
|
||||||
D2@{ shape: bolt }
|
|
||||||
D3@{ shape: disp, label: "a label" }
|
|
||||||
C4@{ shape: junction, label: "a label" }
|
|
||||||
A4@{ shape: extract, label: "a label"}
|
|
||||||
B52[a fr]@{ shape: fr }
|
|
||||||
end
|
|
||||||
subgraph " "
|
|
||||||
A1@{ shape: text, label: This is a textblock}
|
|
||||||
B1@{ shape: card, label: "a label" }
|
|
||||||
C1@{ shape: lined-proc, label: "a label" }
|
|
||||||
D1@{ shape: start, label: "a label" }
|
|
||||||
E1@{ shape: stop, label: "a label" }
|
|
||||||
E2@{ shape: doc, label: "a label" }
|
|
||||||
A6@{ shape: stored-data, label: "a label"}
|
|
||||||
A3@{ shape: delay, label: "a label" }
|
|
||||||
E3@{ shape: div-proc, label: "a label" }
|
|
||||||
B4[a label]@{ shape: win-pane }
|
|
||||||
end
|
|
||||||
</pre>
|
|
||||||
<pre id="diagram" class="mermaid2">
|
|
||||||
---
|
|
||||||
title: hello2
|
|
||||||
config:
|
|
||||||
look: handDrawn
|
|
||||||
elk:
|
|
||||||
<!-- nodePlacementStrategy: SIMPLE -->
|
|
||||||
---
|
|
||||||
%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%
|
|
||||||
flowchart TD
|
|
||||||
|
|
||||||
A([Start]) -->|go to booking page| B("select
|
|
||||||
ISBS booking no")
|
|
||||||
A --> QQ{cancel booking}
|
|
||||||
A --> RR{no show}
|
|
||||||
A --> SS{change booking}
|
|
||||||
B -->C(wmpay_request_payment.request_type= 'partial',
|
|
||||||
wmpay_request_payment.status= 'paid',
|
|
||||||
pos_booking.booking_status= ‘partial’ and 'full_deposit')
|
|
||||||
style C text-align:left
|
|
||||||
C -->D{manage booking}
|
|
||||||
|
|
||||||
D -->|cancel|E[ระบบแสดงช่องให้กรอกเหตุผล]
|
|
||||||
E -->F{กดปุ่ม 'cancel' หรือไม่}
|
|
||||||
F -->|Yes|G[ระบบบันทึกค่าใหม่
|
|
||||||
และไม่สามารถแก้ไขข้อมูลได้]
|
|
||||||
F -->|No|H[กดปุ่ม 'close']
|
|
||||||
H -->|ระบบไม่เปลี่ยนแปลงข้อมูล|Z
|
|
||||||
G -->|ระบบส่งข้อมูล|I[(POS_database)]
|
|
||||||
I -->|pos_booking.booking_status='cancel'|Z([End])
|
|
||||||
|
|
||||||
|
|
||||||
D -->|no show|J[ระบบแสดงช่องให้กรอกเหตุผล]
|
|
||||||
J -->K{กดปุ่ม 'noshow' หรือไม่}
|
|
||||||
K -->|Yes|L[ระบบสร้างใบเสร็จอัตโนมัติ
|
|
||||||
Product_id: 439,
|
|
||||||
ItemName: no show]
|
|
||||||
style L text-align:left
|
|
||||||
|
|
||||||
K -->|No|O[กดปุ่ม 'close']
|
|
||||||
O -->|ระบบไม่เปลี่ยนแปลงข้อมูล|Z
|
|
||||||
L -->M[ระบบบันทึกค่าใหม่]
|
|
||||||
M -->|ระบบส่งข้อมูล|N[(POS_database)]
|
|
||||||
N -->|pos_booking.booking_status=‘noshow’|Z
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</pre>
|
|
||||||
<pre id="diagram" class="mermaid2">
|
|
||||||
---
|
|
||||||
title: hello2
|
|
||||||
config:
|
|
||||||
look: handDrawn
|
|
||||||
layout: dagre
|
|
||||||
elk:
|
|
||||||
nodePlacementStrategy: BRANDES_KOEPF
|
|
||||||
---
|
|
||||||
flowchart
|
|
||||||
A --> A
|
|
||||||
subgraph A
|
|
||||||
B --> B
|
|
||||||
subgraph B
|
|
||||||
C
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
</pre
|
|
||||||
>
|
|
||||||
<pre id="diagram" class="mermaid2">
|
|
||||||
---
|
|
||||||
config:
|
|
||||||
look: handdrawn
|
|
||||||
flowchart:
|
|
||||||
htmlLabels: true
|
|
||||||
---
|
|
||||||
flowchart
|
|
||||||
A[I am a long text, where do I go??? handdrawn - true]
|
|
||||||
</pre
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="flex">
|
|
||||||
<pre id="diagram" class="mermaid2">
|
|
||||||
---
|
|
||||||
config:
|
|
||||||
flowchart:
|
|
||||||
htmlLabels: false
|
|
||||||
---
|
|
||||||
flowchart
|
|
||||||
A[I am a long text, where do I go??? classic - false]
|
|
||||||
</pre
|
|
||||||
>
|
|
||||||
<pre id="diagram" class="mermaid2">
|
|
||||||
---
|
|
||||||
config:
|
|
||||||
flowchart:
|
|
||||||
htmlLabels: true
|
|
||||||
---
|
|
||||||
flowchart
|
|
||||||
A[I am a long text, where do I go??? classic - true]
|
|
||||||
</pre
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<pre id="diagram2" class="mermaid2">
|
|
||||||
flowchart LR
|
|
||||||
id1(Start)-->id2(Stop)
|
|
||||||
style id1 fill:#f9f,stroke:#333,stroke-width:4px
|
|
||||||
style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
|
|
||||||
|
|
||||||
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<pre id="diagram3" class="mermaid2">
|
|
||||||
flowchart LR
|
|
||||||
A:::foo & B:::bar --> C:::foobar
|
|
||||||
classDef foo stroke:#f00
|
|
||||||
classDef bar stroke:#0f0
|
|
||||||
classDef ash color:red
|
|
||||||
class C ash
|
|
||||||
style C stroke:#00f, fill:black
|
|
||||||
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<pre id="diagram4" class="mermaid2">
|
|
||||||
stateDiagram
|
|
||||||
A:::foo
|
|
||||||
B:::bar --> C:::foobar
|
|
||||||
classDef foo stroke:#f00
|
|
||||||
classDef bar stroke:#0f0
|
|
||||||
style C stroke:#00f, fill:black, color:white
|
|
||||||
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<pre id="diagram4" class="mermaid">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart TB
|
kanban
|
||||||
A@{
|
id1[Todo]
|
||||||
label: "aksljhf kasjdh"
|
id2[Create JISON]
|
||||||
}
|
id3[Update DB function]
|
||||||
|
id4[Create parsing tests]
|
||||||
|
id5[define getData]
|
||||||
|
id6[Create renderer]
|
||||||
|
id7[In progress]
|
||||||
|
id8[Design grammar]
|
||||||
</pre>
|
</pre>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import mermaid from './mermaid.esm.mjs';
|
import mermaid from './mermaid.esm.mjs';
|
||||||
@@ -456,7 +123,7 @@ flowchart TB
|
|||||||
messageFontFamily: 'courier',
|
messageFontFamily: 'courier',
|
||||||
},
|
},
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
logLevel: 3,
|
logLevel: 0,
|
||||||
securityLevel: 'loose',
|
securityLevel: 'loose',
|
||||||
});
|
});
|
||||||
function callback() {
|
function callback() {
|
||||||
|
@@ -19,6 +19,7 @@ import errorDiagram from '../diagrams/error/errorDiagram.js';
|
|||||||
import flowchartElk from '../diagrams/flowchart/elk/detector.js';
|
import flowchartElk from '../diagrams/flowchart/elk/detector.js';
|
||||||
import timeline from '../diagrams/timeline/detector.js';
|
import timeline from '../diagrams/timeline/detector.js';
|
||||||
import mindmap from '../diagrams/mindmap/detector.js';
|
import mindmap from '../diagrams/mindmap/detector.js';
|
||||||
|
import kanban from '../diagrams/kanban/detector.js';
|
||||||
import sankey from '../diagrams/sankey/sankeyDetector.js';
|
import sankey from '../diagrams/sankey/sankeyDetector.js';
|
||||||
import { packet } from '../diagrams/packet/detector.js';
|
import { packet } from '../diagrams/packet/detector.js';
|
||||||
import block from '../diagrams/block/blockDetector.js';
|
import block from '../diagrams/block/blockDetector.js';
|
||||||
@@ -70,6 +71,7 @@ export const addDiagrams = () => {
|
|||||||
// Ordering of detectors is important. The first one to return true will be used.
|
// Ordering of detectors is important. The first one to return true will be used.
|
||||||
registerLazyLoadedDiagrams(
|
registerLazyLoadedDiagrams(
|
||||||
c4,
|
c4,
|
||||||
|
kanban,
|
||||||
classDiagramV2,
|
classDiagramV2,
|
||||||
classDiagram,
|
classDiagram,
|
||||||
er,
|
er,
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
// @ts-ignore: JISON doesn't support types
|
// @ts-ignore: JISON doesn't support types
|
||||||
import parser from './parser/mindmap.jison';
|
import parser from './parser/kanban.jison';
|
||||||
import db from './kanbanDb.js';
|
import db from './kanbanDb.js';
|
||||||
import renderer from './kanbanRenderer.js';
|
import renderer from './kanbanRenderer.js';
|
||||||
import styles from './styles.js';
|
import styles from './styles.js';
|
||||||
|
@@ -16,8 +16,9 @@ describe('when parsing a kanban ', function () {
|
|||||||
root`;
|
root`;
|
||||||
|
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
// console.log('Time for checks', kanban.yy.getMindmap().descr);
|
const sections = kanban.yy.getSections();
|
||||||
expect(kanban.yy.getMindmap().descr).toEqual('root');
|
expect(sections.length).toEqual(1);
|
||||||
|
expect(sections[0].descr).toEqual('root');
|
||||||
});
|
});
|
||||||
it('KNBN-2 should handle a hierachial kanban definition', function () {
|
it('KNBN-2 should handle a hierachial kanban definition', function () {
|
||||||
const str = `kanban
|
const str = `kanban
|
||||||
@@ -27,45 +28,59 @@ describe('when parsing a kanban ', function () {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
const mm = kanban.yy.getMindmap();
|
const sections = kanban.yy.getSections();
|
||||||
expect(mm.descr).toEqual('root');
|
expect(sections.length).toEqual(1);
|
||||||
expect(mm.children.length).toEqual(2);
|
expect(sections[0].descr).toEqual('root');
|
||||||
expect(mm.children[0].descr).toEqual('child1');
|
expect(sections[0].children.length).toEqual(2);
|
||||||
expect(mm.children[1].descr).toEqual('child2');
|
expect(sections[0].children[0].descr).toEqual('child1');
|
||||||
|
expect(sections[0].children[1].descr).toEqual('child2');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** CATCH case when a lower level comes later, should throw
|
||||||
|
* a
|
||||||
|
* b
|
||||||
|
* c
|
||||||
|
*/
|
||||||
|
|
||||||
it('3 should handle a simple root definition with a shape and without an id abc123', function () {
|
it('3 should handle a simple root definition with a shape and without an id abc123', function () {
|
||||||
const str = `kanban
|
const str = `kanban
|
||||||
(root)`;
|
(root)`;
|
||||||
|
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
// console.log('Time for checks', kanban.yy.getMindmap().descr);
|
const sections = kanban.yy.getSections();
|
||||||
expect(kanban.yy.getMindmap().descr).toEqual('root');
|
expect(sections[0].descr).toEqual('root');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('KNBN-4 should handle a deeper hierachial kanban definition', function () {
|
it('KNBN-4 should not dsitinguis between deeper hierachial levels in thr kanban definition', function () {
|
||||||
const str = `kanban
|
const str = `kanban
|
||||||
root
|
root
|
||||||
child1
|
child1
|
||||||
leaf1
|
leaf1
|
||||||
child2`;
|
child2`;
|
||||||
|
|
||||||
kanban.parse(str);
|
// less picky is better
|
||||||
const mm = kanban.yy.getMindmap();
|
// expect(() => kanban.parse(str)).toThrow(
|
||||||
expect(mm.descr).toEqual('root');
|
// 'There can be only one root. No parent could be found for ("fakeRoot")'
|
||||||
expect(mm.children.length).toEqual(2);
|
// );
|
||||||
expect(mm.children[0].descr).toEqual('child1');
|
|
||||||
expect(mm.children[0].children[0].descr).toEqual('leaf1');
|
|
||||||
expect(mm.children[1].descr).toEqual('child2');
|
|
||||||
});
|
|
||||||
it('5 Multiple roots are illegal', function () {
|
|
||||||
const str = `kanban
|
|
||||||
root
|
|
||||||
fakeRoot`;
|
|
||||||
|
|
||||||
expect(() => kanban.parse(str)).toThrow(
|
kanban.parse(str);
|
||||||
'There can be only one root. No parent could be found for ("fakeRoot")'
|
const sections = kanban.yy.getSections();
|
||||||
);
|
expect(sections.length).toBe(1);
|
||||||
|
expect(sections[0].children.length).toBe(3);
|
||||||
|
});
|
||||||
|
it('5 Multiple sections are ok', function () {
|
||||||
|
const str = `kanban
|
||||||
|
section1
|
||||||
|
section2`;
|
||||||
|
kanban.parse(str);
|
||||||
|
const sections = kanban.yy.getSections();
|
||||||
|
expect(sections.length).toBe(2);
|
||||||
|
expect(sections[0].descr).toBe('section1');
|
||||||
|
expect(sections[1].descr).toBe('section2');
|
||||||
|
|
||||||
|
// expect(() => kanban.parse(str)).toThrow(
|
||||||
|
// 'There can be only one root. No parent could be found for ("fakeRoot")'
|
||||||
|
// );
|
||||||
});
|
});
|
||||||
it('KNBN-6 real root in wrong place', function () {
|
it('KNBN-6 real root in wrong place', function () {
|
||||||
const str = `kanban
|
const str = `kanban
|
||||||
@@ -73,7 +88,7 @@ describe('when parsing a kanban ', function () {
|
|||||||
fakeRoot
|
fakeRoot
|
||||||
realRootWrongPlace`;
|
realRootWrongPlace`;
|
||||||
expect(() => kanban.parse(str)).toThrow(
|
expect(() => kanban.parse(str)).toThrow(
|
||||||
'There can be only one root. No parent could be found for ("fakeRoot")'
|
'Items without section detected, found section ("fakeRoot")'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -84,10 +99,10 @@ describe('when parsing a kanban ', function () {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
const mm = kanban.yy.getMindmap();
|
const sections = kanban.yy.getSections();
|
||||||
expect(mm.nodeId).toEqual('root');
|
expect(sections[0].nodeId).toEqual('root');
|
||||||
expect(mm.descr).toEqual('The root');
|
expect(sections[0].descr).toEqual('The root');
|
||||||
expect(mm.type).toEqual(kanban.yy.nodeType.RECT);
|
expect(sections[0].type).toEqual(kanban.yy.nodeType.RECT);
|
||||||
});
|
});
|
||||||
it('KNBN-8 should handle an id and type for a node definition', function () {
|
it('KNBN-8 should handle an id and type for a node definition', function () {
|
||||||
const str = `kanban
|
const str = `kanban
|
||||||
@@ -95,10 +110,10 @@ describe('when parsing a kanban ', function () {
|
|||||||
theId(child1)`;
|
theId(child1)`;
|
||||||
|
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
const mm = kanban.yy.getMindmap();
|
const sections = kanban.yy.getSections();
|
||||||
expect(mm.descr).toEqual('root');
|
expect(sections[0].descr).toEqual('root');
|
||||||
expect(mm.children.length).toEqual(1);
|
expect(sections[0].children.length).toEqual(1);
|
||||||
const child = mm.children[0];
|
const child = sections[0].children[0];
|
||||||
expect(child.descr).toEqual('child1');
|
expect(child.descr).toEqual('child1');
|
||||||
expect(child.nodeId).toEqual('theId');
|
expect(child.nodeId).toEqual('theId');
|
||||||
expect(child.type).toEqual(kanban.yy.nodeType.ROUNDED_RECT);
|
expect(child.type).toEqual(kanban.yy.nodeType.ROUNDED_RECT);
|
||||||
@@ -109,10 +124,10 @@ root
|
|||||||
theId(child1)`;
|
theId(child1)`;
|
||||||
|
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
const mm = kanban.yy.getMindmap();
|
const sections = kanban.yy.getSections();
|
||||||
expect(mm.descr).toEqual('root');
|
expect(sections[0].descr).toEqual('root');
|
||||||
expect(mm.children.length).toEqual(1);
|
expect(sections[0].children.length).toEqual(1);
|
||||||
const child = mm.children[0];
|
const child = sections[0].children[0];
|
||||||
expect(child.descr).toEqual('child1');
|
expect(child.descr).toEqual('child1');
|
||||||
expect(child.nodeId).toEqual('theId');
|
expect(child.nodeId).toEqual('theId');
|
||||||
expect(child.type).toEqual(kanban.yy.nodeType.ROUNDED_RECT);
|
expect(child.type).toEqual(kanban.yy.nodeType.ROUNDED_RECT);
|
||||||
@@ -123,10 +138,10 @@ root
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
const mm = kanban.yy.getMindmap();
|
const sections = kanban.yy.getSections();
|
||||||
expect(mm.descr).toEqual('the root');
|
expect(sections[0].descr).toEqual('the root');
|
||||||
expect(mm.children.length).toEqual(0);
|
expect(sections[0].children.length).toEqual(0);
|
||||||
expect(mm.type).toEqual(kanban.yy.nodeType.CIRCLE);
|
expect(sections[0].type).toEqual(kanban.yy.nodeType.CIRCLE);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('KNBN-11 multiple types (cloud)', function () {
|
it('KNBN-11 multiple types (cloud)', function () {
|
||||||
@@ -135,10 +150,10 @@ root
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
const mm = kanban.yy.getMindmap();
|
const sections = kanban.yy.getSections();
|
||||||
expect(mm.descr).toEqual('the root');
|
expect(sections[0].descr).toEqual('the root');
|
||||||
expect(mm.children.length).toEqual(0);
|
expect(sections[0].children.length).toEqual(0);
|
||||||
expect(mm.type).toEqual(kanban.yy.nodeType.CLOUD);
|
expect(sections[0].type).toEqual(kanban.yy.nodeType.CLOUD);
|
||||||
});
|
});
|
||||||
it('KNBN-12 multiple types (bang)', function () {
|
it('KNBN-12 multiple types (bang)', function () {
|
||||||
const str = `kanban
|
const str = `kanban
|
||||||
@@ -146,10 +161,10 @@ root
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
const mm = kanban.yy.getMindmap();
|
const sections = kanban.yy.getSections();
|
||||||
expect(mm.descr).toEqual('the root');
|
expect(sections[0].descr).toEqual('the root');
|
||||||
expect(mm.children.length).toEqual(0);
|
expect(sections[0].children.length).toEqual(0);
|
||||||
expect(mm.type).toEqual(kanban.yy.nodeType.BANG);
|
expect(sections[0].type).toEqual(kanban.yy.nodeType.BANG);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('KNBN-12-a multiple types (hexagon)', function () {
|
it('KNBN-12-a multiple types (hexagon)', function () {
|
||||||
@@ -158,10 +173,10 @@ root
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
const mm = kanban.yy.getMindmap();
|
const sections = kanban.yy.getSections();
|
||||||
expect(mm.type).toEqual(kanban.yy.nodeType.HEXAGON);
|
expect(sections[0].type).toEqual(kanban.yy.nodeType.HEXAGON);
|
||||||
expect(mm.descr).toEqual('the root');
|
expect(sections[0].descr).toEqual('the root');
|
||||||
expect(mm.children.length).toEqual(0);
|
expect(sections[0].children.length).toEqual(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('decorations', function () {
|
describe('decorations', function () {
|
||||||
@@ -173,11 +188,11 @@ root
|
|||||||
// ::class1 class2
|
// ::class1 class2
|
||||||
|
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
const mm = kanban.yy.getMindmap();
|
const sections = kanban.yy.getSections();
|
||||||
expect(mm.nodeId).toEqual('root');
|
expect(sections[0].nodeId).toEqual('root');
|
||||||
expect(mm.descr).toEqual('The root');
|
expect(sections[0].descr).toEqual('The root');
|
||||||
expect(mm.type).toEqual(kanban.yy.nodeType.RECT);
|
expect(sections[0].type).toEqual(kanban.yy.nodeType.RECT);
|
||||||
expect(mm.icon).toEqual('bomb');
|
expect(sections[0].icon).toEqual('bomb');
|
||||||
});
|
});
|
||||||
it('KNBN-14 should be possible to set classes for the node', function () {
|
it('KNBN-14 should be possible to set classes for the node', function () {
|
||||||
const str = `kanban
|
const str = `kanban
|
||||||
@@ -187,11 +202,11 @@ root
|
|||||||
// ::class1 class2
|
// ::class1 class2
|
||||||
|
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
const mm = kanban.yy.getMindmap();
|
const sections = kanban.yy.getSections();
|
||||||
expect(mm.nodeId).toEqual('root');
|
expect(sections[0].nodeId).toEqual('root');
|
||||||
expect(mm.descr).toEqual('The root');
|
expect(sections[0].descr).toEqual('The root');
|
||||||
expect(mm.type).toEqual(kanban.yy.nodeType.RECT);
|
expect(sections[0].type).toEqual(kanban.yy.nodeType.RECT);
|
||||||
expect(mm.class).toEqual('m-4 p-8');
|
expect(sections[0].class).toEqual('m-4 p-8');
|
||||||
});
|
});
|
||||||
it('KNBN-15 should be possible to set both classes and icon for the node', function () {
|
it('KNBN-15 should be possible to set both classes and icon for the node', function () {
|
||||||
const str = `kanban
|
const str = `kanban
|
||||||
@@ -202,12 +217,12 @@ root
|
|||||||
// ::class1 class2
|
// ::class1 class2
|
||||||
|
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
const mm = kanban.yy.getMindmap();
|
const sections = kanban.yy.getSections();
|
||||||
expect(mm.nodeId).toEqual('root');
|
expect(sections[0].nodeId).toEqual('root');
|
||||||
expect(mm.descr).toEqual('The root');
|
expect(sections[0].descr).toEqual('The root');
|
||||||
expect(mm.type).toEqual(kanban.yy.nodeType.RECT);
|
expect(sections[0].type).toEqual(kanban.yy.nodeType.RECT);
|
||||||
expect(mm.class).toEqual('m-4 p-8');
|
expect(sections[0].class).toEqual('m-4 p-8');
|
||||||
expect(mm.icon).toEqual('bomb');
|
expect(sections[0].icon).toEqual('bomb');
|
||||||
});
|
});
|
||||||
it('KNBN-16 should be possible to set both classes and icon for the node', function () {
|
it('KNBN-16 should be possible to set both classes and icon for the node', function () {
|
||||||
const str = `kanban
|
const str = `kanban
|
||||||
@@ -218,12 +233,12 @@ root
|
|||||||
// ::class1 class2
|
// ::class1 class2
|
||||||
|
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
const mm = kanban.yy.getMindmap();
|
const sections = kanban.yy.getSections();
|
||||||
expect(mm.nodeId).toEqual('root');
|
expect(sections[0].nodeId).toEqual('root');
|
||||||
expect(mm.descr).toEqual('The root');
|
expect(sections[0].descr).toEqual('The root');
|
||||||
expect(mm.type).toEqual(kanban.yy.nodeType.RECT);
|
expect(sections[0].type).toEqual(kanban.yy.nodeType.RECT);
|
||||||
expect(mm.class).toEqual('m-4 p-8');
|
expect(sections[0].class).toEqual('m-4 p-8');
|
||||||
expect(mm.icon).toEqual('bomb');
|
expect(sections[0].icon).toEqual('bomb');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('descriptions', function () {
|
describe('descriptions', function () {
|
||||||
@@ -232,9 +247,9 @@ root
|
|||||||
root["String containing []"]
|
root["String containing []"]
|
||||||
`;
|
`;
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
const mm = kanban.yy.getMindmap();
|
const sections = kanban.yy.getSections();
|
||||||
expect(mm.nodeId).toEqual('root');
|
expect(sections[0].nodeId).toEqual('root');
|
||||||
expect(mm.descr).toEqual('String containing []');
|
expect(sections[0].descr).toEqual('String containing []');
|
||||||
});
|
});
|
||||||
it('KNBN-18 should be possible to use node syntax in the descriptions in children', function () {
|
it('KNBN-18 should be possible to use node syntax in the descriptions in children', function () {
|
||||||
const str = `kanban
|
const str = `kanban
|
||||||
@@ -242,11 +257,11 @@ root
|
|||||||
child1["String containing ()"]
|
child1["String containing ()"]
|
||||||
`;
|
`;
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
const mm = kanban.yy.getMindmap();
|
const sections = kanban.yy.getSections();
|
||||||
expect(mm.nodeId).toEqual('root');
|
expect(sections[0].nodeId).toEqual('root');
|
||||||
expect(mm.descr).toEqual('String containing []');
|
expect(sections[0].descr).toEqual('String containing []');
|
||||||
expect(mm.children.length).toEqual(1);
|
expect(sections[0].children.length).toEqual(1);
|
||||||
expect(mm.children[0].descr).toEqual('String containing ()');
|
expect(sections[0].children[0].descr).toEqual('String containing ()');
|
||||||
});
|
});
|
||||||
it('KNBN-19 should be possible to have a child after a class assignment', function () {
|
it('KNBN-19 should be possible to have a child after a class assignment', function () {
|
||||||
const str = `kanban
|
const str = `kanban
|
||||||
@@ -256,16 +271,17 @@ root
|
|||||||
a(a)
|
a(a)
|
||||||
b[New Stuff]`;
|
b[New Stuff]`;
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
const mm = kanban.yy.getMindmap();
|
const sections = kanban.yy.getSections();
|
||||||
expect(mm.nodeId).toEqual('root');
|
expect(sections[0].nodeId).toEqual('root');
|
||||||
expect(mm.descr).toEqual('Root');
|
expect(sections[0].descr).toEqual('Root');
|
||||||
expect(mm.children.length).toEqual(1);
|
expect(sections[0].children.length).toEqual(3);
|
||||||
|
|
||||||
const child = mm.children[0];
|
const item1 = sections[0].children[0];
|
||||||
expect(child.nodeId).toEqual('Child');
|
const item2 = sections[0].children[1];
|
||||||
expect(child.children[0].nodeId).toEqual('a');
|
const item3 = sections[0].children[2];
|
||||||
expect(child.children.length).toEqual(2);
|
expect(item1.nodeId).toEqual('Child');
|
||||||
expect(child.children[1].nodeId).toEqual('b');
|
expect(item2.nodeId).toEqual('a');
|
||||||
|
expect(item3.nodeId).toEqual('b');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('KNBN-20 should be possible to have meaningless empty rows in a kanban abc124', function () {
|
it('KNBN-20 should be possible to have meaningless empty rows in a kanban abc124', function () {
|
||||||
@@ -276,16 +292,17 @@ root
|
|||||||
|
|
||||||
b[New Stuff]`;
|
b[New Stuff]`;
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
const mm = kanban.yy.getMindmap();
|
const sections = kanban.yy.getSections();
|
||||||
expect(mm.nodeId).toEqual('root');
|
expect(sections[0].nodeId).toEqual('root');
|
||||||
expect(mm.descr).toEqual('Root');
|
expect(sections[0].descr).toEqual('Root');
|
||||||
expect(mm.children.length).toEqual(1);
|
expect(sections[0].children.length).toEqual(3);
|
||||||
|
|
||||||
const child = mm.children[0];
|
const item1 = sections[0].children[0];
|
||||||
expect(child.nodeId).toEqual('Child');
|
const item2 = sections[0].children[1];
|
||||||
expect(child.children[0].nodeId).toEqual('a');
|
const item3 = sections[0].children[2];
|
||||||
expect(child.children.length).toEqual(2);
|
expect(item1.nodeId).toEqual('Child');
|
||||||
expect(child.children[1].nodeId).toEqual('b');
|
expect(item2.nodeId).toEqual('a');
|
||||||
|
expect(item3.nodeId).toEqual('b');
|
||||||
});
|
});
|
||||||
it('KNBN-21 should be possible to have comments in a kanban', function () {
|
it('KNBN-21 should be possible to have comments in a kanban', function () {
|
||||||
const str = `kanban
|
const str = `kanban
|
||||||
@@ -296,16 +313,15 @@ root
|
|||||||
%% This is a comment
|
%% This is a comment
|
||||||
b[New Stuff]`;
|
b[New Stuff]`;
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
const mm = kanban.yy.getMindmap();
|
const sections = kanban.yy.getSections();
|
||||||
expect(mm.nodeId).toEqual('root');
|
expect(sections[0].nodeId).toEqual('root');
|
||||||
expect(mm.descr).toEqual('Root');
|
expect(sections[0].descr).toEqual('Root');
|
||||||
expect(mm.children.length).toEqual(1);
|
|
||||||
|
|
||||||
const child = mm.children[0];
|
const child = sections[0].children[0];
|
||||||
expect(child.nodeId).toEqual('Child');
|
expect(child.nodeId).toEqual('Child');
|
||||||
expect(child.children[0].nodeId).toEqual('a');
|
expect(sections[0].children[1].nodeId).toEqual('a');
|
||||||
expect(child.children.length).toEqual(2);
|
expect(sections[0].children[2].nodeId).toEqual('b');
|
||||||
expect(child.children[1].nodeId).toEqual('b');
|
expect(sections[0].children.length).toEqual(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('KNBN-22 should be possible to have comments at the end of a line', function () {
|
it('KNBN-22 should be possible to have comments at the end of a line', function () {
|
||||||
@@ -315,51 +331,52 @@ root
|
|||||||
a(a) %% This is a comment
|
a(a) %% This is a comment
|
||||||
b[New Stuff]`;
|
b[New Stuff]`;
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
const mm = kanban.yy.getMindmap();
|
const sections = kanban.yy.getSections();
|
||||||
expect(mm.nodeId).toEqual('root');
|
expect(sections[0].nodeId).toEqual('root');
|
||||||
expect(mm.descr).toEqual('Root');
|
expect(sections[0].descr).toEqual('Root');
|
||||||
expect(mm.children.length).toEqual(1);
|
expect(sections[0].children.length).toEqual(3);
|
||||||
|
|
||||||
const child = mm.children[0];
|
const child1 = sections[0].children[0];
|
||||||
expect(child.nodeId).toEqual('Child');
|
expect(child1.nodeId).toEqual('Child');
|
||||||
expect(child.children[0].nodeId).toEqual('a');
|
const child2 = sections[0].children[1];
|
||||||
expect(child.children.length).toEqual(2);
|
expect(child2.nodeId).toEqual('a');
|
||||||
expect(child.children[1].nodeId).toEqual('b');
|
const child3 = sections[0].children[2];
|
||||||
|
expect(child3.nodeId).toEqual('b');
|
||||||
});
|
});
|
||||||
it('KNBN-23 Rows with only spaces should not interfere', function () {
|
it('KNBN-23 Rows with only spaces should not interfere', function () {
|
||||||
const str = 'kanban\nroot\n A\n \n\n B';
|
const str = 'kanban\nroot\n A\n \n\n B';
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
const mm = kanban.yy.getMindmap();
|
const sections = kanban.yy.getSections();
|
||||||
expect(mm.nodeId).toEqual('root');
|
expect(sections[0].nodeId).toEqual('root');
|
||||||
expect(mm.children.length).toEqual(2);
|
expect(sections[0].children.length).toEqual(2);
|
||||||
|
|
||||||
const child = mm.children[0];
|
const child = sections[0].children[0];
|
||||||
expect(child.nodeId).toEqual('A');
|
expect(child.nodeId).toEqual('A');
|
||||||
const child2 = mm.children[1];
|
const child2 = sections[0].children[1];
|
||||||
expect(child2.nodeId).toEqual('B');
|
expect(child2.nodeId).toEqual('B');
|
||||||
});
|
});
|
||||||
it('KNBN-24 Handle rows above the kanban declarations', function () {
|
it('KNBN-24 Handle rows above the kanban declarations', function () {
|
||||||
const str = '\n \nkanban\nroot\n A\n \n\n B';
|
const str = '\n \nkanban\nroot\n A\n \n\n B';
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
const mm = kanban.yy.getMindmap();
|
const sections = kanban.yy.getSections();
|
||||||
expect(mm.nodeId).toEqual('root');
|
expect(sections[0].nodeId).toEqual('root');
|
||||||
expect(mm.children.length).toEqual(2);
|
expect(sections[0].children.length).toEqual(2);
|
||||||
|
|
||||||
const child = mm.children[0];
|
const child = sections[0].children[0];
|
||||||
expect(child.nodeId).toEqual('A');
|
expect(child.nodeId).toEqual('A');
|
||||||
const child2 = mm.children[1];
|
const child2 = sections[0].children[1];
|
||||||
expect(child2.nodeId).toEqual('B');
|
expect(child2.nodeId).toEqual('B');
|
||||||
});
|
});
|
||||||
it('KNBN-25 Handle rows above the kanban declarations, no space', function () {
|
it('KNBN-25 Handle rows above the kanban declarations, no space', function () {
|
||||||
const str = '\n\n\nkanban\nroot\n A\n \n\n B';
|
const str = '\n\n\nkanban\nroot\n A\n \n\n B';
|
||||||
kanban.parse(str);
|
kanban.parse(str);
|
||||||
const mm = kanban.yy.getMindmap();
|
const sections = kanban.yy.getSections();
|
||||||
expect(mm.nodeId).toEqual('root');
|
expect(sections[0].nodeId).toEqual('root');
|
||||||
expect(mm.children.length).toEqual(2);
|
expect(sections[0].children.length).toEqual(2);
|
||||||
|
|
||||||
const child = mm.children[0];
|
const child = sections[0].children[0];
|
||||||
expect(child.nodeId).toEqual('A');
|
expect(child.nodeId).toEqual('A');
|
||||||
const child2 = mm.children[1];
|
const child2 = sections[0].children[1];
|
||||||
expect(child2.nodeId).toEqual('B');
|
expect(child2.nodeId).toEqual('B');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -2,35 +2,75 @@ import { getConfig } from '../../diagram-api/diagramAPI.js';
|
|||||||
import type { D3Element } from '../../types.js';
|
import type { D3Element } from '../../types.js';
|
||||||
import { sanitizeText } from '../../diagrams/common/common.js';
|
import { sanitizeText } from '../../diagrams/common/common.js';
|
||||||
import { log } from '../../logger.js';
|
import { log } from '../../logger.js';
|
||||||
import type { MindmapNode } from './kanbanTypes.js';
|
import type { KanbanNode } from './kanbanTypes.js';
|
||||||
|
import type { Node, Edge } from '../../rendering-util/types.js';
|
||||||
import defaultConfig from '../../defaultConfig.js';
|
import defaultConfig from '../../defaultConfig.js';
|
||||||
|
|
||||||
let nodes: MindmapNode[] = [];
|
let nodes: KanbanNode[] = [];
|
||||||
|
let sections: KanbanNode[] = [];
|
||||||
let cnt = 0;
|
let cnt = 0;
|
||||||
let elements: Record<number, D3Element> = {};
|
let elements: Record<number, D3Element> = {};
|
||||||
|
|
||||||
const clear = () => {
|
const clear = () => {
|
||||||
nodes = [];
|
nodes = [];
|
||||||
|
sections = [];
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
elements = {};
|
elements = {};
|
||||||
};
|
};
|
||||||
|
/*
|
||||||
const getParent = function (level: number) {
|
* if your level is the section level return null - then you do not belong to a level
|
||||||
|
* otherwise return the current section
|
||||||
|
*/
|
||||||
|
const getSection = function (level: number) {
|
||||||
|
if (nodes.length === 0) {
|
||||||
|
// console.log('No nodes');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const sectionLevel = nodes[0].level;
|
||||||
|
let lastSection = null;
|
||||||
for (let i = nodes.length - 1; i >= 0; i--) {
|
for (let i = nodes.length - 1; i >= 0; i--) {
|
||||||
if (nodes[i].level < level) {
|
if (nodes[i].level === sectionLevel && !lastSection) {
|
||||||
return nodes[i];
|
lastSection = nodes[i];
|
||||||
|
// console.log('lastSection found', lastSection);
|
||||||
|
}
|
||||||
|
// console.log('HERE', nodes[i].id, level, nodes[i].level, sectionLevel);
|
||||||
|
if (nodes[i].level < sectionLevel) {
|
||||||
|
throw new Error('Items without section detected, found section ("' + nodes[i].descr + '")');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No parent found
|
// if (!lastSection) {
|
||||||
return null;
|
// // console.log('No last section');
|
||||||
|
// }
|
||||||
|
if (level === lastSection?.level) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No found
|
||||||
|
return lastSection;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getMindmap = () => {
|
const getSections = function () {
|
||||||
return nodes.length > 0 ? nodes[0] : null;
|
console.log('sections', sections);
|
||||||
|
return sections;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getData = function () {
|
||||||
|
const edges = [] as Edge[];
|
||||||
|
const nodes: Node[] = [];
|
||||||
|
|
||||||
|
// const id: string = sanitizeText(id, conf) || 'identifier' + cnt++;
|
||||||
|
|
||||||
|
// const node = {
|
||||||
|
// id,
|
||||||
|
// label: sanitizeText(descr, conf),
|
||||||
|
// isGroup,
|
||||||
|
// } satisfies Node;
|
||||||
|
|
||||||
|
return { nodes, edges, other: {}, config: getConfig() };
|
||||||
};
|
};
|
||||||
|
|
||||||
const addNode = (level: number, id: string, descr: string, type: number) => {
|
const addNode = (level: number, id: string, descr: string, type: number) => {
|
||||||
log.info('addNode', level, id, descr, type);
|
// log.info('addNode level=', level, 'id=', id, 'descr=', descr, 'type=', type);
|
||||||
const conf = getConfig();
|
const conf = getConfig();
|
||||||
let padding: number = conf.mindmap?.padding ?? defaultConfig.mindmap.padding;
|
let padding: number = conf.mindmap?.padding ?? defaultConfig.mindmap.padding;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -49,24 +89,17 @@ const addNode = (level: number, id: string, descr: string, type: number) => {
|
|||||||
children: [],
|
children: [],
|
||||||
width: conf.mindmap?.maxNodeWidth ?? defaultConfig.mindmap.maxNodeWidth,
|
width: conf.mindmap?.maxNodeWidth ?? defaultConfig.mindmap.maxNodeWidth,
|
||||||
padding,
|
padding,
|
||||||
} satisfies MindmapNode;
|
} satisfies KanbanNode;
|
||||||
|
const section = getSection(level);
|
||||||
const parent = getParent(level);
|
console.log('Node ', node.descr, ' section', section?.descr);
|
||||||
if (parent) {
|
if (section) {
|
||||||
parent.children.push(node);
|
section.children.push(node);
|
||||||
// Keep all nodes in the list
|
// Keep all nodes in the list
|
||||||
nodes.push(node);
|
nodes.push(node);
|
||||||
} else {
|
} else {
|
||||||
if (nodes.length === 0) {
|
sections.push(node);
|
||||||
// First node, the root
|
|
||||||
nodes.push(node);
|
|
||||||
} else {
|
|
||||||
// Syntax error ... there can only bee one root
|
|
||||||
throw new Error(
|
|
||||||
'There can be only one root. No parent could be found for ("' + node.descr + '")'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
nodes.push(node);
|
||||||
};
|
};
|
||||||
|
|
||||||
const nodeType = {
|
const nodeType = {
|
||||||
@@ -146,7 +179,8 @@ const getElementById = (id: number) => elements[id];
|
|||||||
const db = {
|
const db = {
|
||||||
clear,
|
clear,
|
||||||
addNode,
|
addNode,
|
||||||
getMindmap,
|
getSections,
|
||||||
|
getData,
|
||||||
nodeType,
|
nodeType,
|
||||||
getType,
|
getType,
|
||||||
setElementForId,
|
setElementForId,
|
||||||
|
@@ -9,29 +9,13 @@ import { log } from '../../logger.js';
|
|||||||
import type { D3Element } from '../../types.js';
|
import type { D3Element } from '../../types.js';
|
||||||
import { selectSvgElement } from '../../rendering-util/selectSvgElement.js';
|
import { selectSvgElement } from '../../rendering-util/selectSvgElement.js';
|
||||||
import { setupGraphViewbox } from '../../setupGraphViewbox.js';
|
import { setupGraphViewbox } from '../../setupGraphViewbox.js';
|
||||||
import type { FilledMindMapNode, MindmapDB, MindmapNode } from './kanbanTypes.js';
|
import type { FilledKanbanNode, KanbanDB, KanbanNode } from './kanbanTypes.js';
|
||||||
import { drawNode, positionNode } from './svgDraw.js';
|
import { drawNode, positionNode } from './svgDraw.js';
|
||||||
import defaultConfig from '../../defaultConfig.js';
|
import defaultConfig from '../../defaultConfig.js';
|
||||||
|
|
||||||
// Inject the layout algorithm into cytoscape
|
// Inject the layout algorithm into cytoscape
|
||||||
cytoscape.use(coseBilkent);
|
|
||||||
|
|
||||||
async function drawNodes(
|
async function drawSection(section: FilledKanbanNode, svg: D3Element, conf: MermaidConfig) {}
|
||||||
db: MindmapDB,
|
|
||||||
svg: D3Element,
|
|
||||||
mindmap: FilledMindMapNode,
|
|
||||||
section: number,
|
|
||||||
conf: MermaidConfig
|
|
||||||
) {
|
|
||||||
await drawNode(db, svg, mindmap, section, conf);
|
|
||||||
if (mindmap.children) {
|
|
||||||
await Promise.all(
|
|
||||||
mindmap.children.map((child, index) =>
|
|
||||||
drawNodes(db, svg, child, section < 0 ? index : section, conf)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'cytoscape' {
|
declare module 'cytoscape' {
|
||||||
interface EdgeSingular {
|
interface EdgeSingular {
|
||||||
@@ -66,7 +50,7 @@ function drawEdges(edgesEl: D3Element, cy: cytoscape.Core) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function addNodes(mindmap: MindmapNode, cy: cytoscape.Core, conf: MermaidConfig, level: number) {
|
function addNodes(mindmap: KanbanNode, cy: cytoscape.Core, conf: MermaidConfig, level: number) {
|
||||||
cy.add({
|
cy.add({
|
||||||
group: 'nodes',
|
group: 'nodes',
|
||||||
data: {
|
data: {
|
||||||
@@ -101,7 +85,7 @@ function addNodes(mindmap: MindmapNode, cy: cytoscape.Core, conf: MermaidConfig,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function layoutMindmap(node: MindmapNode, conf: MermaidConfig): Promise<cytoscape.Core> {
|
function layoutMindmap(node: KanbanNode, conf: MermaidConfig): Promise<cytoscape.Core> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
// Add temporary render element
|
// Add temporary render element
|
||||||
const renderEl = select('body').append('div').attr('id', 'cy').attr('style', 'display:none');
|
const renderEl = select('body').append('div').attr('id', 'cy').attr('style', 'display:none');
|
||||||
@@ -142,7 +126,7 @@ function layoutMindmap(node: MindmapNode, conf: MermaidConfig): Promise<cytoscap
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function positionNodes(db: MindmapDB, cy: cytoscape.Core) {
|
function positionNodes(db: KanbanDB, cy: cytoscape.Core) {
|
||||||
cy.nodes().map((node, id) => {
|
cy.nodes().map((node, id) => {
|
||||||
const data = node.data();
|
const data = node.data();
|
||||||
data.x = node.position().x;
|
data.x = node.position().x;
|
||||||
@@ -161,9 +145,10 @@ function positionNodes(db: MindmapDB, cy: cytoscape.Core) {
|
|||||||
export const draw: DrawDefinition = async (text, id, _version, diagObj) => {
|
export const draw: DrawDefinition = async (text, id, _version, diagObj) => {
|
||||||
log.debug('Rendering mindmap diagram\n' + text);
|
log.debug('Rendering mindmap diagram\n' + text);
|
||||||
|
|
||||||
const db = diagObj.db as MindmapDB;
|
const db = diagObj.db as KanbanDB;
|
||||||
const mm = db.getMindmap();
|
const sections = db.getSections();
|
||||||
if (!mm) {
|
// const sections = db.getData();
|
||||||
|
if (!sections) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,14 +161,14 @@ export const draw: DrawDefinition = async (text, id, _version, diagObj) => {
|
|||||||
// this gives us the size of the nodes and we can set the positions later
|
// this gives us the size of the nodes and we can set the positions later
|
||||||
|
|
||||||
const edgesElem = svg.append('g');
|
const edgesElem = svg.append('g');
|
||||||
edgesElem.attr('class', 'mindmap-edges');
|
edgesElem.attr('class', 'sections');
|
||||||
const nodesElem = svg.append('g');
|
const nodesElem = svg.append('g');
|
||||||
nodesElem.attr('class', 'mindmap-nodes');
|
nodesElem.attr('class', 'items');
|
||||||
await drawNodes(db, nodesElem, mm as FilledMindMapNode, -1, conf);
|
await drawSections(db, nodesElem, sections as FilledKanbanNode, -1, conf);
|
||||||
|
|
||||||
// Next step is to layout the mindmap, giving each node a position
|
// Next step is to layout the mindmap, giving each node a position
|
||||||
|
|
||||||
const cy = await layoutMindmap(mm, conf);
|
const cy = await layoutMindmap(sections, conf);
|
||||||
|
|
||||||
// After this we can draw, first the edges and the then nodes with the correct position
|
// After this we can draw, first the edges and the then nodes with the correct position
|
||||||
drawEdges(edgesElem, cy);
|
drawEdges(edgesElem, cy);
|
||||||
|
@@ -1,13 +1,13 @@
|
|||||||
import type { RequiredDeep } from 'type-fest';
|
import type { RequiredDeep } from 'type-fest';
|
||||||
import type mindmapDb from './kanbanDb.js';
|
import type kanbanDb from './kanbanDb.js';
|
||||||
|
|
||||||
export interface MindmapNode {
|
export interface KanbanNode {
|
||||||
id: number;
|
id: number;
|
||||||
nodeId: string;
|
nodeId: string;
|
||||||
level: number;
|
level: number;
|
||||||
descr: string;
|
descr: string;
|
||||||
type: number;
|
type: number;
|
||||||
children: MindmapNode[];
|
children: KanbanNode[];
|
||||||
width: number;
|
width: number;
|
||||||
padding: number;
|
padding: number;
|
||||||
section?: number;
|
section?: number;
|
||||||
@@ -18,5 +18,5 @@ export interface MindmapNode {
|
|||||||
y?: number;
|
y?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FilledMindMapNode = RequiredDeep<MindmapNode>;
|
export type FilledKanbanNode = RequiredDeep<KanbanNode>;
|
||||||
export type MindmapDB = typeof mindmapDb;
|
export type KanbanDB = typeof kanbanDb;
|
||||||
|
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
\s*\%\%.* {yy.getLogger().trace('Found comment',yytext); return 'SPACELINE';}
|
\s*\%\%.* {yy.getLogger().trace('Found comment',yytext); return 'SPACELINE';}
|
||||||
// \%\%[^\n]*\n /* skip comments */
|
// \%\%[^\n]*\n /* skip comments */
|
||||||
"kanban" return 'MINDMAP';
|
"kanban" return 'KANBAN';
|
||||||
":::" { this.begin('CLASS'); }
|
":::" { this.begin('CLASS'); }
|
||||||
<CLASS>.+ { this.popState();return 'CLASS'; }
|
<CLASS>.+ { this.popState();return 'CLASS'; }
|
||||||
<CLASS>\n { this.popState();}
|
<CLASS>\n { this.popState();}
|
||||||
@@ -80,8 +80,8 @@ spaceLines
|
|||||||
;
|
;
|
||||||
|
|
||||||
mindMap
|
mindMap
|
||||||
: MINDMAP document { return yy; }
|
: KANBAN document { return yy; }
|
||||||
| MINDMAP NL document { return yy; }
|
| KANBAN NL document { return yy; }
|
||||||
;
|
;
|
||||||
|
|
||||||
stop
|
stop
|
||||||
|
105
packages/mermaid/src/diagrams/kanban/samples.md
Normal file
105
packages/mermaid/src/diagrams/kanban/samples.md
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
```mermaid
|
||||||
|
kanban
|
||||||
|
New
|
||||||
|
Sometimes wrong Shape type is highlighted
|
||||||
|
In progress
|
||||||
|
|
||||||
|
|
||||||
|
````
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
kanban
|
||||||
|
Todo
|
||||||
|
Create JISON
|
||||||
|
Update DB function
|
||||||
|
Create parsing tests
|
||||||
|
define getData
|
||||||
|
Create renderer
|
||||||
|
In progress
|
||||||
|
Design grammar
|
||||||
|
|
||||||
|
````
|
||||||
|
|
||||||
|
Adding ID
|
||||||
|
```mermaid
|
||||||
|
kanban
|
||||||
|
id1[Todo]
|
||||||
|
id2[Create JISON]
|
||||||
|
id3[Update DB function]
|
||||||
|
id4[Create parsing tests]
|
||||||
|
id5[define getData]
|
||||||
|
id6[Create renderer]
|
||||||
|
id7[In progress]
|
||||||
|
id8[Design grammar]
|
||||||
|
|
||||||
|
````
|
||||||
|
|
||||||
|
Background color for section
|
||||||
|
```mermaid
|
||||||
|
kanban
|
||||||
|
id1[Todo]
|
||||||
|
id2[Create JISON]
|
||||||
|
id3[Update DB function]
|
||||||
|
id4[Create parsing tests]
|
||||||
|
id5[define getData]
|
||||||
|
id6[Create renderer]
|
||||||
|
id7[In progress]
|
||||||
|
id8[Design grammar]
|
||||||
|
|
||||||
|
style n2 stroke:#AA00FF,fill:#E1BEE7
|
||||||
|
````
|
||||||
|
|
||||||
|
Background color for section
|
||||||
|
```mermaid
|
||||||
|
kanban
|
||||||
|
id1[Todo]
|
||||||
|
id2[Create JISON]
|
||||||
|
id3[Update DB function]
|
||||||
|
id4[Create parsing tests]
|
||||||
|
id5[define getData]
|
||||||
|
id6[Create renderer]
|
||||||
|
id7[In progress]
|
||||||
|
id8[Design grammar]
|
||||||
|
|
||||||
|
id2@{
|
||||||
|
assigned: knsv
|
||||||
|
icon: heart
|
||||||
|
priority: high
|
||||||
|
descr: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
|
||||||
|
}
|
||||||
|
style n1 stroke:#AA00FF,fill:#E1BEE7
|
||||||
|
````
|
||||||
|
|
||||||
|
|
||||||
|
Background color for section
|
||||||
|
```mermaid
|
||||||
|
---
|
||||||
|
config:
|
||||||
|
kanban:
|
||||||
|
showIds: true
|
||||||
|
fields: [[title],[description][id, assigned]]
|
||||||
|
---
|
||||||
|
kanban
|
||||||
|
id1[Todo]
|
||||||
|
id2[Create JISON]
|
||||||
|
id3[Update DB function]
|
||||||
|
id4[Create parsing tests]
|
||||||
|
id5[define getData]
|
||||||
|
id6[Create renderer]
|
||||||
|
id7[In progress]
|
||||||
|
id8[Design grammar]
|
||||||
|
|
||||||
|
id2@{
|
||||||
|
assigned: knsv
|
||||||
|
icon: heart
|
||||||
|
priority: high
|
||||||
|
descr: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
|
||||||
|
}
|
||||||
|
style n1 stroke:#AA00FF,fill:#E1BEE7
|
||||||
|
````
|
||||||
|
|
||||||
|
|
||||||
|
priority - dedicated
|
||||||
|
link - dedicated
|
@@ -1,5 +1,5 @@
|
|||||||
import { createText } from '../../rendering-util/createText.js';
|
import { createText } from '../../rendering-util/createText.js';
|
||||||
import type { FilledMindMapNode, MindmapDB } from './kanbanTypes.js';
|
import type { FilledKanbanNode, KanbanDB } from './kanbanTypes.js';
|
||||||
import type { Point, D3Element } from '../../types.js';
|
import type { Point, D3Element } from '../../types.js';
|
||||||
import { parseFontSize } from '../../utils.js';
|
import { parseFontSize } from '../../utils.js';
|
||||||
import type { MermaidConfig } from '../../config.type.js';
|
import type { MermaidConfig } from '../../config.type.js';
|
||||||
@@ -7,9 +7,9 @@ import type { MermaidConfig } from '../../config.type.js';
|
|||||||
const MAX_SECTIONS = 12;
|
const MAX_SECTIONS = 12;
|
||||||
|
|
||||||
type ShapeFunction = (
|
type ShapeFunction = (
|
||||||
db: MindmapDB,
|
db: KanbanDB,
|
||||||
elem: D3Element,
|
elem: D3Element,
|
||||||
node: FilledMindMapNode,
|
node: FilledKanbanNode,
|
||||||
section?: number
|
section?: number
|
||||||
) => void;
|
) => void;
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ function insertPolygonShape(
|
|||||||
w: number,
|
w: number,
|
||||||
h: number,
|
h: number,
|
||||||
points: Point[],
|
points: Point[],
|
||||||
node: FilledMindMapNode
|
node: FilledKanbanNode
|
||||||
) {
|
) {
|
||||||
return parent
|
return parent
|
||||||
.insert('polygon', ':first-child')
|
.insert('polygon', ':first-child')
|
||||||
@@ -136,9 +136,9 @@ function insertPolygonShape(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const hexagonBkg: ShapeFunction = function (
|
const hexagonBkg: ShapeFunction = function (
|
||||||
_db: MindmapDB,
|
_db: KanbanDB,
|
||||||
elem: D3Element,
|
elem: D3Element,
|
||||||
node: FilledMindMapNode
|
node: FilledKanbanNode
|
||||||
) {
|
) {
|
||||||
const h = node.height;
|
const h = node.height;
|
||||||
const f = 4;
|
const f = 4;
|
||||||
@@ -175,9 +175,9 @@ const roundedRectBkg: ShapeFunction = function (db, elem, node) {
|
|||||||
* @returns The height nodes dom element
|
* @returns The height nodes dom element
|
||||||
*/
|
*/
|
||||||
export const drawNode = async function (
|
export const drawNode = async function (
|
||||||
db: MindmapDB,
|
db: KanbanDB,
|
||||||
elem: D3Element,
|
elem: D3Element,
|
||||||
node: FilledMindMapNode,
|
node: FilledKanbanNode,
|
||||||
fullSection: number,
|
fullSection: number,
|
||||||
conf: MermaidConfig
|
conf: MermaidConfig
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
@@ -298,7 +298,7 @@ export const drawNode = async function (
|
|||||||
return node.height;
|
return node.height;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const positionNode = function (db: MindmapDB, node: FilledMindMapNode) {
|
export const positionNode = function (db: KanbanDB, node: FilledKanbanNode) {
|
||||||
const nodeElem = db.getElementById(node.id);
|
const nodeElem = db.getElementById(node.id);
|
||||||
|
|
||||||
const x = node.x || 0;
|
const x = node.x || 0;
|
||||||
|
@@ -280,6 +280,127 @@ const roundedWithTitle = async (parent, node) => {
|
|||||||
|
|
||||||
return { cluster: shapeSvg, labelBBox: bbox };
|
return { cluster: shapeSvg, labelBBox: bbox };
|
||||||
};
|
};
|
||||||
|
const kanbanSection = async (parent, node) => {
|
||||||
|
const siteConfig = getConfig();
|
||||||
|
|
||||||
|
const { themeVariables, handDrawnSeed } = siteConfig;
|
||||||
|
const { altBackground, compositeBackground, compositeTitleBackground, nodeBorder } =
|
||||||
|
themeVariables;
|
||||||
|
|
||||||
|
// Add outer g element
|
||||||
|
const shapeSvg = parent
|
||||||
|
.insert('g')
|
||||||
|
.attr('class', node.cssClasses)
|
||||||
|
.attr('id', node.id)
|
||||||
|
.attr('data-id', node.id)
|
||||||
|
.attr('data-look', node.look);
|
||||||
|
|
||||||
|
// add the rect
|
||||||
|
const outerRectG = shapeSvg.insert('g', ':first-child');
|
||||||
|
|
||||||
|
// Create the label and insert it after the rect
|
||||||
|
const label = shapeSvg.insert('g').attr('class', 'cluster-label');
|
||||||
|
let innerRect = shapeSvg.append('rect');
|
||||||
|
|
||||||
|
const text = label
|
||||||
|
.node()
|
||||||
|
.appendChild(await createLabel(node.label, node.labelStyle, undefined, true));
|
||||||
|
|
||||||
|
// Get the size of the label
|
||||||
|
let bbox = text.getBBox();
|
||||||
|
|
||||||
|
if (evaluate(siteConfig.flowchart.htmlLabels)) {
|
||||||
|
const div = text.children[0];
|
||||||
|
const dv = select(text);
|
||||||
|
bbox = div.getBoundingClientRect();
|
||||||
|
dv.attr('width', bbox.width);
|
||||||
|
dv.attr('height', bbox.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rounded With Title
|
||||||
|
const padding = 0 * node.padding;
|
||||||
|
const halfPadding = padding / 2;
|
||||||
|
|
||||||
|
const width =
|
||||||
|
(node.width <= bbox.width + node.padding ? bbox.width + node.padding : node.width) + padding;
|
||||||
|
if (node.width <= bbox.width + node.padding) {
|
||||||
|
node.diff = (width - node.width) / 2 - node.padding;
|
||||||
|
} else {
|
||||||
|
node.diff = -node.padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
const height = node.height + padding;
|
||||||
|
// const height = node.height + padding;
|
||||||
|
const innerHeight = node.height + padding - bbox.height - 6;
|
||||||
|
const x = node.x - width / 2;
|
||||||
|
const y = node.y - height / 2;
|
||||||
|
node.width = width;
|
||||||
|
const innerY = node.y - node.height / 2 - halfPadding + bbox.height + 2;
|
||||||
|
|
||||||
|
// add the rect
|
||||||
|
let rect;
|
||||||
|
if (node.look === 'handDrawn') {
|
||||||
|
const isAlt = node.cssClasses.includes('statediagram-cluster-alt');
|
||||||
|
const rc = rough.svg(shapeSvg);
|
||||||
|
const roughOuterNode =
|
||||||
|
node.rx || node.ry
|
||||||
|
? rc.path(createRoundedRectPathD(x, y, width, height, 10), {
|
||||||
|
roughness: 0.7,
|
||||||
|
fill: compositeTitleBackground,
|
||||||
|
fillStyle: 'solid',
|
||||||
|
stroke: nodeBorder,
|
||||||
|
seed: handDrawnSeed,
|
||||||
|
})
|
||||||
|
: rc.rectangle(x, y, width, height, { seed: handDrawnSeed });
|
||||||
|
|
||||||
|
rect = shapeSvg.insert(() => roughOuterNode, ':first-child');
|
||||||
|
const roughInnerNode = rc.rectangle(x, innerY, width, innerHeight, {
|
||||||
|
fill: isAlt ? altBackground : compositeBackground,
|
||||||
|
fillStyle: isAlt ? 'hachure' : 'solid',
|
||||||
|
stroke: nodeBorder,
|
||||||
|
seed: handDrawnSeed,
|
||||||
|
});
|
||||||
|
|
||||||
|
rect = shapeSvg.insert(() => roughOuterNode, ':first-child');
|
||||||
|
innerRect = shapeSvg.insert(() => roughInnerNode);
|
||||||
|
} else {
|
||||||
|
rect = outerRectG.insert('rect', ':first-child');
|
||||||
|
const outerRectClass = 'outer';
|
||||||
|
|
||||||
|
// center the rect around its coordinate
|
||||||
|
rect
|
||||||
|
.attr('class', outerRectClass)
|
||||||
|
.attr('x', x)
|
||||||
|
.attr('y', y)
|
||||||
|
.attr('width', width)
|
||||||
|
.attr('height', height)
|
||||||
|
.attr('data-look', node.look);
|
||||||
|
innerRect
|
||||||
|
.attr('class', 'inner')
|
||||||
|
.attr('x', x)
|
||||||
|
.attr('y', innerY)
|
||||||
|
.attr('width', width)
|
||||||
|
.attr('height', innerHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
label.attr(
|
||||||
|
'transform',
|
||||||
|
`translate(${node.x - bbox.width / 2}, ${y + 1 - (evaluate(siteConfig.flowchart.htmlLabels) ? 0 : 3)})`
|
||||||
|
);
|
||||||
|
|
||||||
|
const rectBox = rect.node().getBBox();
|
||||||
|
node.height = rectBox.height;
|
||||||
|
node.offsetX = 0;
|
||||||
|
// Used by layout engine to position subgraph in parent
|
||||||
|
node.offsetY = bbox.height - node.padding / 2;
|
||||||
|
node.labelBBox = bbox;
|
||||||
|
|
||||||
|
node.intersect = function (point) {
|
||||||
|
return intersectRect(node, point);
|
||||||
|
};
|
||||||
|
|
||||||
|
return { cluster: shapeSvg, labelBBox: bbox };
|
||||||
|
};
|
||||||
const divider = (parent, node) => {
|
const divider = (parent, node) => {
|
||||||
const siteConfig = getConfig();
|
const siteConfig = getConfig();
|
||||||
|
|
||||||
@@ -355,6 +476,7 @@ const shapes = {
|
|||||||
roundedWithTitle,
|
roundedWithTitle,
|
||||||
noteGroup,
|
noteGroup,
|
||||||
divider,
|
divider,
|
||||||
|
kanbanSection,
|
||||||
};
|
};
|
||||||
|
|
||||||
let clusterElems = new Map();
|
let clusterElems = new Map();
|
||||||
|
Reference in New Issue
Block a user