mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-22 00:40:22 +02:00
Merge pull request #1370 from mermaid-js/feature/1295_generic_rendering_engine
Feature/1295 generic rendering engine
This commit is contained in:
358
cypress/integration/rendering/stateDiagram-v2.spec.js
Normal file
358
cypress/integration/rendering/stateDiagram-v2.spec.js
Normal file
@@ -0,0 +1,358 @@
|
|||||||
|
/* eslint-env jest */
|
||||||
|
import { imgSnapshotTest } from '../../helpers/util';
|
||||||
|
|
||||||
|
describe('State diagram', () => {
|
||||||
|
it('should render a simple info', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
info
|
||||||
|
`,
|
||||||
|
{ logLevel: 1 }
|
||||||
|
);
|
||||||
|
cy.get('svg');
|
||||||
|
});
|
||||||
|
it('should render a simple state diagrams', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
|
||||||
|
[*] --> State1
|
||||||
|
State1 --> [*]
|
||||||
|
`,
|
||||||
|
{ logLevel: 0 }
|
||||||
|
);
|
||||||
|
cy.get('svg');
|
||||||
|
});
|
||||||
|
it('should render a long descriptions instead of id when available', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
|
||||||
|
[*] --> S1
|
||||||
|
state "Some long name" as S1
|
||||||
|
`,
|
||||||
|
{ logLevel: 0 }
|
||||||
|
);
|
||||||
|
cy.get('svg');
|
||||||
|
});
|
||||||
|
it('should render a long descriptions with additional descriptions', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
|
||||||
|
[*] --> S1
|
||||||
|
state "Some long name" as S1: The description
|
||||||
|
`,
|
||||||
|
{ logLevel: 0 }
|
||||||
|
);
|
||||||
|
cy.get('svg');
|
||||||
|
});
|
||||||
|
it('should render a single state with short descr', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
state "A long long name" as long1
|
||||||
|
state "A" as longlonglongid
|
||||||
|
`,
|
||||||
|
{ logLevel: 0 }
|
||||||
|
);
|
||||||
|
cy.get('svg');
|
||||||
|
});
|
||||||
|
it('should render a transition descrions with new lines', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
|
||||||
|
[*] --> S1
|
||||||
|
S1 --> S2: long line using<br/>should work
|
||||||
|
S1 --> S3: long line using <br>should work
|
||||||
|
S1 --> S4: long line using \\nshould work
|
||||||
|
`,
|
||||||
|
{ logLevel: 0 }
|
||||||
|
);
|
||||||
|
cy.get('svg');
|
||||||
|
});
|
||||||
|
it('should render a state with a note', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
State1: The state with a note
|
||||||
|
note right of State1
|
||||||
|
Important information! You can write
|
||||||
|
notes.
|
||||||
|
end note
|
||||||
|
`,
|
||||||
|
{ logLevel: 0 }
|
||||||
|
);
|
||||||
|
cy.get('svg');
|
||||||
|
});
|
||||||
|
it('should render a state with on the left side when so specified', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
State1: The state with a note with minus - and plus + in it
|
||||||
|
note left of State1
|
||||||
|
Important information! You can write
|
||||||
|
notes with . and in them.
|
||||||
|
end note
|
||||||
|
`,
|
||||||
|
{ logLevel: 0 }
|
||||||
|
);
|
||||||
|
cy.get('svg');
|
||||||
|
});
|
||||||
|
it('should render a state with a note together with another state', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
State1: The state with a note +,-
|
||||||
|
note right of State1
|
||||||
|
Important information! You can write +,-
|
||||||
|
notes.
|
||||||
|
end note
|
||||||
|
State1 --> State2 : With +,-
|
||||||
|
note left of State2 : This is the note +,-<br/>
|
||||||
|
`,
|
||||||
|
{ logLevel: 0 }
|
||||||
|
);
|
||||||
|
cy.get('svg');
|
||||||
|
});
|
||||||
|
it('should render a note with multiple lines in it', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
State1: The state with a note
|
||||||
|
note right of State1
|
||||||
|
Important information! You\ncan write
|
||||||
|
notes with multiple lines...
|
||||||
|
Here is another line...
|
||||||
|
And another line...
|
||||||
|
end note
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should handle multiline notes with different line breaks', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
State1
|
||||||
|
note right of State1
|
||||||
|
Line1<br>Line2<br/>Line3<br />Line4<br />Line5
|
||||||
|
end note
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render a states with descriptions including multi-line descriptions', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
State1: This a a single line description
|
||||||
|
State2: This a a multi line description
|
||||||
|
State2: here comes the multi part
|
||||||
|
[*] --> State1
|
||||||
|
State1 --> State2
|
||||||
|
State2 --> [*]
|
||||||
|
`,
|
||||||
|
{ logLevel: 0 }
|
||||||
|
);
|
||||||
|
cy.get('svg');
|
||||||
|
});
|
||||||
|
it('should render a simple state diagrams', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
[*] --> State1
|
||||||
|
State1 --> State2
|
||||||
|
State1 --> State3
|
||||||
|
State1 --> [*]
|
||||||
|
`,
|
||||||
|
{ logLevel: 0 }
|
||||||
|
);
|
||||||
|
cy.get('svg');
|
||||||
|
});
|
||||||
|
it('should render a simple state diagrams with labels', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
[*] --> State1
|
||||||
|
State1 --> State2 : Transition 1
|
||||||
|
State1 --> State3 : Transition 2
|
||||||
|
State1 --> State4 : Transition 3
|
||||||
|
State1 --> State5 : Transition 4
|
||||||
|
State2 --> State3 : Transition 5
|
||||||
|
State1 --> [*]
|
||||||
|
`,
|
||||||
|
{ logLevel: 0 }
|
||||||
|
);
|
||||||
|
cy.get('svg');
|
||||||
|
});
|
||||||
|
it('should render state descriptions', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
state "Long state description" as XState1
|
||||||
|
state "Another Long state description" as XState2
|
||||||
|
XState2 : New line
|
||||||
|
XState1 --> XState2
|
||||||
|
`,
|
||||||
|
{ logLevel: 0 }
|
||||||
|
);
|
||||||
|
cy.get('svg');
|
||||||
|
});
|
||||||
|
it('should render composit states', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
[*] --> NotShooting: Pacifist
|
||||||
|
NotShooting --> A
|
||||||
|
NotShooting --> B
|
||||||
|
NotShooting --> C
|
||||||
|
|
||||||
|
state NotShooting {
|
||||||
|
[*] --> Idle: Yet another long long öong öong öong label
|
||||||
|
Idle --> Configuring : EvConfig
|
||||||
|
Configuring --> Idle : EvConfig EvConfig EvConfig EvConfig EvConfig
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{ logLevel: 0 }
|
||||||
|
);
|
||||||
|
cy.get('svg');
|
||||||
|
});
|
||||||
|
it('should render multiple composit states', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
[*]-->TV
|
||||||
|
|
||||||
|
state TV {
|
||||||
|
[*] --> Off: Off to start with
|
||||||
|
On --> Off : Turn off
|
||||||
|
Off --> On : Turn on
|
||||||
|
}
|
||||||
|
|
||||||
|
TV--> Console
|
||||||
|
|
||||||
|
state Console {
|
||||||
|
[*] --> Off2: Off to start with
|
||||||
|
On2--> Off2 : Turn off
|
||||||
|
Off2 --> On2 : Turn on
|
||||||
|
On2-->Playing
|
||||||
|
|
||||||
|
state Playing {
|
||||||
|
Alive --> Dead
|
||||||
|
Dead-->Alive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{ logLevel: 0 }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should render forks in composit states', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
[*]-->TV
|
||||||
|
|
||||||
|
state TV {
|
||||||
|
state fork_state <<fork>>
|
||||||
|
[*] --> fork_state
|
||||||
|
fork_state --> State2
|
||||||
|
fork_state --> State3
|
||||||
|
|
||||||
|
state join_state <<join>>
|
||||||
|
State2 --> join_state
|
||||||
|
State3 --> join_state
|
||||||
|
join_state --> State4
|
||||||
|
State4 --> [*]
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{ logLevel: 0 }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should render forks and joins', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
state fork_state <<fork>>
|
||||||
|
[*] --> fork_state
|
||||||
|
fork_state --> State2
|
||||||
|
fork_state --> State3
|
||||||
|
|
||||||
|
state join_state <<join>>
|
||||||
|
State2 --> join_state
|
||||||
|
State3 --> join_state
|
||||||
|
join_state --> State4
|
||||||
|
State4 --> [*]
|
||||||
|
`,
|
||||||
|
{ logLevel: 0 }
|
||||||
|
);
|
||||||
|
cy.get('svg');
|
||||||
|
});
|
||||||
|
it('should render concurrency states', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
[*] --> Active
|
||||||
|
|
||||||
|
state Active {
|
||||||
|
[*] --> NumLockOff
|
||||||
|
NumLockOff --> NumLockOn : EvNumLockPressed
|
||||||
|
NumLockOn --> NumLockOff : EvNumLockPressed
|
||||||
|
--
|
||||||
|
[*] --> CapsLockOff
|
||||||
|
CapsLockOff --> CapsLockOn : EvCapsLockPressed
|
||||||
|
CapsLockOn --> CapsLockOff : EvCapsLockPressed
|
||||||
|
--
|
||||||
|
[*] --> ScrollLockOff
|
||||||
|
ScrollLockOff --> ScrollLockOn : EvCapsLockPressed
|
||||||
|
ScrollLockOn --> ScrollLockOff : EvCapsLockPressed
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{ logLevel: 0 }
|
||||||
|
);
|
||||||
|
cy.get('svg');
|
||||||
|
});
|
||||||
|
it('should render a state with states in it', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
state PilotCockpit {
|
||||||
|
state Parent {
|
||||||
|
C
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{
|
||||||
|
logLevel: 0,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('Simplest composit state', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
state Parent {
|
||||||
|
C
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{
|
||||||
|
logLevel: 0,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('should handle multiple arrows from one node to another', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
a --> b: Start
|
||||||
|
a --> b: Stop
|
||||||
|
`,
|
||||||
|
{
|
||||||
|
logLevel: 0,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@@ -18,6 +18,14 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>info below</h1>
|
<h1>info below</h1>
|
||||||
|
<div class="mermaid2" style="width: 100%; height: 20%;">
|
||||||
|
flowchart LR
|
||||||
|
a --> b
|
||||||
|
|
||||||
|
subgraph b [Test]
|
||||||
|
c --> d -->e
|
||||||
|
end
|
||||||
|
</div>
|
||||||
<div class="mermaid2" style="width: 100%; height: 20%;">
|
<div class="mermaid2" style="width: 100%; height: 20%;">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
a --> b
|
a --> b
|
||||||
@@ -31,30 +39,40 @@
|
|||||||
G-->H
|
G-->H
|
||||||
G-->c
|
G-->c
|
||||||
</div>
|
</div>
|
||||||
<div class="mermaid2" style="width: 50%; height: 20%;">
|
<div class="mermaid" style="width: 50%; height: 20%;">
|
||||||
stateDiagram-v2
|
stateDiagram-v2
|
||||||
[*] --> monkey
|
[*] --> Active
|
||||||
state monkey {
|
|
||||||
Sitting
|
state Active {
|
||||||
--
|
[*] --> NumLockOff
|
||||||
Eating
|
NumLockOff --> NumLockOn : EvNumLockPressed
|
||||||
}
|
NumLockOn --> NumLockOff : EvNumLockPressed
|
||||||
|
--
|
||||||
|
[*] --> CapsLockOff
|
||||||
|
CapsLockOff --> CapsLockOn : EvCapsLockPressed
|
||||||
|
CapsLockOn --> CapsLockOff : EvCapsLockPressed
|
||||||
|
--
|
||||||
|
[*] --> ScrollLockOff
|
||||||
|
ScrollLockOff --> ScrollLockOn : EvCapsLockPressed
|
||||||
|
ScrollLockOn --> ScrollLockOff : EvCapsLockPressed
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="mermaid2" style="width: 50%; height: 20%;">
|
<div class="mermaid2" style="width: 50%; height: 20%;">
|
||||||
stateDiagram-v2
|
stateDiagram-v2
|
||||||
state Active {
|
[*]-->TV
|
||||||
[*] --> NumLockOff
|
|
||||||
NumLockOff --> NumLockOn : EvNumLockPressed
|
state TV {
|
||||||
NumLockOn --> NumLockOff : EvNumLockPressed
|
state fork_state <<fork>>
|
||||||
--
|
[*] --> fork_state
|
||||||
[*] --> CapsLockOff
|
fork_state --> State2
|
||||||
CapsLockOff --> CapsLockOn : EvCapsLockPressed
|
fork_state --> State3
|
||||||
CapsLockOn --> CapsLockOff : EvCapsLockPressed
|
|
||||||
--
|
state join_state <<join>>
|
||||||
[*] --> ScrollLockOff
|
State2 --> join_state
|
||||||
ScrollLockOff --> ScrollLockOn : EvCapsLockPressed
|
State3 --> join_state
|
||||||
ScrollLockOn --> ScrollLockOff : EvCapsLockPressed
|
join_state --> State4
|
||||||
}
|
State4 --> [*]
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="mermaid2 mermaid-apa" style="width: 100%; height: 20%;">
|
<div class="mermaid2 mermaid-apa" style="width: 100%; height: 20%;">
|
||||||
stateDiagram
|
stateDiagram
|
||||||
@@ -73,8 +91,8 @@
|
|||||||
<div class="mermaid2" style="width: 100%; height: 100%;">
|
<div class="mermaid2" style="width: 100%; height: 100%;">
|
||||||
stateDiagram-v2
|
stateDiagram-v2
|
||||||
[*] --> First
|
[*] --> First
|
||||||
First --> Second
|
First --> Third
|
||||||
% First --> Third
|
First --> sec
|
||||||
|
|
||||||
state First {
|
state First {
|
||||||
[*] --> fir
|
[*] --> fir
|
||||||
@@ -83,9 +101,14 @@ stateDiagram-v2
|
|||||||
state Second {
|
state Second {
|
||||||
[*] --> sec
|
[*] --> sec
|
||||||
sec --> [*]
|
sec --> [*]
|
||||||
}
|
}
|
||||||
|
state Third {
|
||||||
|
[*] --> thi
|
||||||
|
thi --> [*]
|
||||||
|
}
|
||||||
|
thi --> sec
|
||||||
</div>
|
</div>
|
||||||
<div class="mermaid" style="width: 100%; height: 100%;">
|
<div class="mermaid2" style="width: 100%; height: 100%;">
|
||||||
flowchart TD
|
flowchart TD
|
||||||
subgraph A
|
subgraph A
|
||||||
a
|
a
|
||||||
@@ -101,7 +124,7 @@ flowchart TD
|
|||||||
A -- oAo --o B
|
A -- oAo --o B
|
||||||
A --> C
|
A --> C
|
||||||
</div>
|
</div>
|
||||||
<div class="mermaid" style="width: 100%; height: 100%;">
|
<div class="mermaid2" style="width: 100%; height: 100%;">
|
||||||
flowchart TD
|
flowchart TD
|
||||||
subgraph A
|
subgraph A
|
||||||
a
|
a
|
||||||
@@ -133,28 +156,27 @@ stateDiagram-v2
|
|||||||
</div>
|
</div>
|
||||||
<div class="mermaid2" style="width: 100%; height: 100%;">
|
<div class="mermaid2" style="width: 100%; height: 100%;">
|
||||||
stateDiagram-v2
|
stateDiagram-v2
|
||||||
[*]-->TV
|
[*]-->TV
|
||||||
|
|
||||||
state TV {
|
state TV {
|
||||||
[*] --> Off: Off to start with
|
[*] --> Off: Off to start with
|
||||||
On --> Off : Turn off
|
On --> Off : Turn off
|
||||||
Off --> On : Turn on
|
Off --> On : Turn on
|
||||||
}
|
}
|
||||||
|
|
||||||
TV--> Console
|
TV--> Console
|
||||||
|
|
||||||
state Console {
|
state Console {
|
||||||
[*] --> Off2: Off to start with
|
[*] --> Off2: Off to start with
|
||||||
On2--> Off2 : Turn off
|
On2--> Off2 : Turn off
|
||||||
Off2 --> On2 : Turn on
|
Off2 --> On2 : Turn on
|
||||||
On2-->Playing
|
On2-->Playing
|
||||||
|
|
||||||
state Playing {
|
|
||||||
Alive --> Dead
|
|
||||||
Dead-->Alive
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
state Playing {
|
||||||
|
Alive --> Dead
|
||||||
|
Dead-->Alive
|
||||||
|
}
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="display: flex;flex-direction:column;width: 100%; height: 100%">
|
<div style="display: flex;flex-direction:column;width: 100%; height: 100%">
|
||||||
|
@@ -100,6 +100,20 @@ double_arrow_circle
|
|||||||
Lets try to make these types semantic free so that diagram type semantics does not find its way in to this more generic layer.
|
Lets try to make these types semantic free so that diagram type semantics does not find its way in to this more generic layer.
|
||||||
|
|
||||||
|
|
||||||
|
Required edgeData for proper rendering:
|
||||||
|
|
||||||
|
| property | description |
|
||||||
|
| ---------- | ---------------------------------------- |
|
||||||
|
| id | Id of the edge |
|
||||||
|
| arrowHead | overlap between arrowHead and arrowType? |
|
||||||
|
| arrowType | overlap between arrowHead and arrowType? |
|
||||||
|
| style | |
|
||||||
|
| labelStyle | |
|
||||||
|
| label | overlap between label and labelText? |
|
||||||
|
| labelPos | |
|
||||||
|
| labelType | overlap between label and labelText? |
|
||||||
|
|
||||||
|
|
||||||
# Markers
|
# Markers
|
||||||
|
|
||||||
Define what markers that should be included in the diagram with the insert markers function. The function takes two arguments, first the element in which the markers should be included and a list of the markers that should be added.
|
Define what markers that should be included in the diagram with the insert markers function. The function takes two arguments, first the element in which the markers should be included and a list of the markers that should be added.
|
||||||
|
@@ -149,7 +149,39 @@ const roundedWithTitle = (parent, node) => {
|
|||||||
return shapeSvg;
|
return shapeSvg;
|
||||||
};
|
};
|
||||||
|
|
||||||
const shapes = { rect, roundedWithTitle, noteGroup };
|
const divider = (parent, node) => {
|
||||||
|
// Add outer g element
|
||||||
|
const shapeSvg = parent
|
||||||
|
.insert('g')
|
||||||
|
.attr('class', node.classes)
|
||||||
|
.attr('id', node.id);
|
||||||
|
|
||||||
|
// add the rect
|
||||||
|
const rect = shapeSvg.insert('rect', ':first-child');
|
||||||
|
|
||||||
|
const padding = 0 * node.padding;
|
||||||
|
const halfPadding = padding / 2;
|
||||||
|
|
||||||
|
// center the rect around its coordinate
|
||||||
|
rect
|
||||||
|
.attr('class', 'divider')
|
||||||
|
.attr('x', node.x - node.width / 2 - halfPadding)
|
||||||
|
.attr('y', node.y - node.height / 2)
|
||||||
|
.attr('width', node.width + padding)
|
||||||
|
.attr('height', node.height + padding);
|
||||||
|
|
||||||
|
const rectBox = rect.node().getBBox();
|
||||||
|
node.width = rectBox.width;
|
||||||
|
node.height = rectBox.height;
|
||||||
|
|
||||||
|
node.intersect = function(point) {
|
||||||
|
return intersectRect(node, point);
|
||||||
|
};
|
||||||
|
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
||||||
|
|
||||||
|
const shapes = { rect, roundedWithTitle, noteGroup, divider };
|
||||||
|
|
||||||
let clusterElems = {};
|
let clusterElems = {};
|
||||||
|
|
||||||
|
@@ -1,9 +1,13 @@
|
|||||||
const createLabel = (vertexText, style) => {
|
const createLabel = (vertexText, style, isTitle) => {
|
||||||
const svgLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text');
|
const svgLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text');
|
||||||
svgLabel.setAttribute('style', style.replace('color:', 'fill:'));
|
svgLabel.setAttribute('style', style.replace('color:', 'fill:'));
|
||||||
let rows = [];
|
let rows = [];
|
||||||
if (vertexText) {
|
if (typeof vertexText === 'string') {
|
||||||
rows = vertexText.split(/\n|<br\s*\/?>/gi);
|
rows = vertexText.split(/\\n|\n|<br\s*\/?>/gi);
|
||||||
|
} else if (Array.isArray(vertexText)) {
|
||||||
|
rows = vertexText;
|
||||||
|
} else {
|
||||||
|
rows = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let j = 0; j < rows.length; j++) {
|
for (let j = 0; j < rows.length; j++) {
|
||||||
@@ -11,6 +15,11 @@ const createLabel = (vertexText, style) => {
|
|||||||
tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
|
tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
|
||||||
tspan.setAttribute('dy', '1em');
|
tspan.setAttribute('dy', '1em');
|
||||||
tspan.setAttribute('x', '0');
|
tspan.setAttribute('x', '0');
|
||||||
|
if (isTitle) {
|
||||||
|
tspan.setAttribute('class', 'title-row');
|
||||||
|
} else {
|
||||||
|
tspan.setAttribute('class', 'row');
|
||||||
|
}
|
||||||
tspan.textContent = rows[j].trim();
|
tspan.textContent = rows[j].trim();
|
||||||
svgLabel.appendChild(tspan);
|
svgLabel.appendChild(tspan);
|
||||||
}
|
}
|
||||||
|
@@ -33,6 +33,7 @@ export const insertEdgeLabel = (elem, edge) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const positionEdgeLabel = edge => {
|
export const positionEdgeLabel = edge => {
|
||||||
|
logger.info('Moving label', edge.id, edge.label, edgeLabels[edge.id]);
|
||||||
const el = edgeLabels[edge.id];
|
const el = edgeLabels[edge.id];
|
||||||
el.attr('transform', 'translate(' + edge.x + ', ' + edge.y + ')');
|
el.attr('transform', 'translate(' + edge.x + ', ' + edge.y + ')');
|
||||||
};
|
};
|
||||||
|
@@ -14,7 +14,10 @@ import { insertEdgeLabel, positionEdgeLabel, insertEdge, clear as clearEdges } f
|
|||||||
import { logger as log } from '../logger';
|
import { logger as log } from '../logger';
|
||||||
|
|
||||||
const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
|
const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
|
||||||
log.trace('Graph in recursive render:', graphlib.json.write(graph), parentCluster);
|
log.info('Graph in recursive render:', graphlib.json.write(graph), parentCluster);
|
||||||
|
const dir = graph.graph().rankdir;
|
||||||
|
log.warn('Dir in recursive render - dir:', dir);
|
||||||
|
|
||||||
const elem = _elem.insert('g').attr('class', 'root'); // eslint-disable-line
|
const elem = _elem.insert('g').attr('class', 'root'); // eslint-disable-line
|
||||||
if (!graph.nodes()) {
|
if (!graph.nodes()) {
|
||||||
log.trace('No nodes found for', graph);
|
log.trace('No nodes found for', graph);
|
||||||
@@ -59,7 +62,7 @@ const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
|
|||||||
// insertCluster(clusters, graph.node(v));
|
// insertCluster(clusters, graph.node(v));
|
||||||
} else {
|
} else {
|
||||||
log.trace('Node - the non recursive path', v, node.id, node);
|
log.trace('Node - the non recursive path', v, node.id, node);
|
||||||
insertNode(nodes, graph.node(v));
|
insertNode(nodes, graph.node(v), dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -79,14 +82,14 @@ const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
graph.edges().forEach(function(e) {
|
graph.edges().forEach(function(e) {
|
||||||
log.trace('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(e));
|
log.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(e));
|
||||||
});
|
});
|
||||||
log.trace('#############################################');
|
log.info('#############################################');
|
||||||
log.trace('### Layout ###');
|
log.info('### Layout ###');
|
||||||
log.trace('#############################################');
|
log.info('#############################################');
|
||||||
log.trace(graph);
|
log.info(graph);
|
||||||
dagre.layout(graph);
|
dagre.layout(graph);
|
||||||
log.warn('Graph after layout:', graphlib.json.write(graph));
|
log.trace('Graph after layout:', graphlib.json.write(graph));
|
||||||
// Move the nodes to the correct place
|
// Move the nodes to the correct place
|
||||||
graph.nodes().forEach(function(v) {
|
graph.nodes().forEach(function(v) {
|
||||||
const node = graph.node(v);
|
const node = graph.node(v);
|
||||||
@@ -119,7 +122,7 @@ const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
|
|||||||
// Move the edge labels to the correct place after layout
|
// Move the edge labels to the correct place after layout
|
||||||
graph.edges().forEach(function(e) {
|
graph.edges().forEach(function(e) {
|
||||||
const edge = graph.edge(e);
|
const edge = graph.edge(e);
|
||||||
log.trace('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(edge), edge);
|
log.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(edge), edge);
|
||||||
|
|
||||||
insertEdge(edgePaths, edge, clusterDb, diagramtype);
|
insertEdge(edgePaths, edge, clusterDb, diagramtype);
|
||||||
positionEdgeLabel(edge);
|
positionEdgeLabel(edge);
|
||||||
@@ -138,7 +141,7 @@ export const render = (elem, graph, markers, diagramtype, id) => {
|
|||||||
log.warn('Graph before:', graphlib.json.write(graph));
|
log.warn('Graph before:', graphlib.json.write(graph));
|
||||||
adjustClustersAndEdges(graph);
|
adjustClustersAndEdges(graph);
|
||||||
log.warn('Graph after:', graphlib.json.write(graph));
|
log.warn('Graph after:', graphlib.json.write(graph));
|
||||||
|
log.warn('Graph ever after:', graph.graph());
|
||||||
recursiveRender(elem, graph, diagramtype);
|
recursiveRender(elem, graph, diagramtype);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -31,13 +31,17 @@ const isDecendant = (id, ancenstorId) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const edgeInCluster = (edge, clusterId) => {
|
const edgeInCluster = (edge, clusterId) => {
|
||||||
|
log.info('Decendants of ', clusterId, ' is ', decendants[clusterId]);
|
||||||
|
log.info('Edge is ', edge);
|
||||||
// Edges to/from the cluster is not in the cluster, they are in the parent
|
// Edges to/from the cluster is not in the cluster, they are in the parent
|
||||||
if (!(edge.v === clusterId || edge.w === clusterId)) return false;
|
if (edge.v === clusterId) return false;
|
||||||
|
if (edge.w === clusterId) return false;
|
||||||
|
|
||||||
if (!decendants[clusterId]) {
|
if (!decendants[clusterId]) {
|
||||||
log.debug('Tilt, ', clusterId, ',not in decendants');
|
log.debug('Tilt, ', clusterId, ',not in decendants');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
log.info('Here ');
|
||||||
|
|
||||||
if (decendants[clusterId].indexOf(edge.v) >= 0) return true;
|
if (decendants[clusterId].indexOf(edge.v) >= 0) return true;
|
||||||
if (isDecendant(edge.v, clusterId)) return true;
|
if (isDecendant(edge.v, clusterId)) return true;
|
||||||
@@ -80,17 +84,26 @@ const copy = (clusterId, graph, newGraph, rootId) => {
|
|||||||
const edges = graph.edges(node);
|
const edges = graph.edges(node);
|
||||||
log.debug('Copying Edges', edges);
|
log.debug('Copying Edges', edges);
|
||||||
edges.forEach(edge => {
|
edges.forEach(edge => {
|
||||||
log.trace('Edge', edge);
|
log.info('Edge', edge);
|
||||||
const data = graph.edge(edge.v, edge.w, edge.name);
|
const data = graph.edge(edge.v, edge.w, edge.name);
|
||||||
log.trace('Edge data', data, rootId);
|
log.info('Edge data', data, rootId);
|
||||||
try {
|
try {
|
||||||
// Do not copy edges in and out of the root cluster, they belong to the parent graph
|
// Do not copy edges in and out of the root cluster, they belong to the parent graph
|
||||||
if (edgeInCluster(edge, rootId)) {
|
if (edgeInCluster(edge, rootId)) {
|
||||||
log.trace('Copying as ', edge.v, edge.w, data, edge.name);
|
log.info('Copying as ', edge.v, edge.w, data, edge.name);
|
||||||
newGraph.setEdge(edge.v, edge.w, data, edge.name);
|
newGraph.setEdge(edge.v, edge.w, data, edge.name);
|
||||||
log.trace('newGraph edges ', newGraph.edges(), newGraph.edge(newGraph.edges()[0]));
|
log.info('newGraph edges ', newGraph.edges(), newGraph.edge(newGraph.edges()[0]));
|
||||||
} else {
|
} else {
|
||||||
log.trace('Skipping copy of edge as ', rootId, edge.v, edge.w, clusterId);
|
log.info(
|
||||||
|
'Skipping copy of edge ',
|
||||||
|
edge.v,
|
||||||
|
'-->',
|
||||||
|
edge.w,
|
||||||
|
' rootId: ',
|
||||||
|
rootId,
|
||||||
|
' clusterId:',
|
||||||
|
clusterId
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error(e);
|
log.error(e);
|
||||||
@@ -316,12 +329,14 @@ export const extractor = (graph, depth) => {
|
|||||||
depth
|
depth
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const graphSettings = graph.graph();
|
||||||
|
|
||||||
const clusterGraph = new graphlib.Graph({
|
const clusterGraph = new graphlib.Graph({
|
||||||
multigraph: true,
|
multigraph: true,
|
||||||
compound: true
|
compound: true
|
||||||
})
|
})
|
||||||
.setGraph({
|
.setGraph({
|
||||||
rankdir: 'TB',
|
rankdir: graphSettings.rankdir === 'TB' ? 'LR' : 'TB',
|
||||||
// Todo: set proper spacing
|
// Todo: set proper spacing
|
||||||
nodesep: 50,
|
nodesep: 50,
|
||||||
ranksep: 50,
|
ranksep: 50,
|
||||||
|
@@ -314,6 +314,34 @@ describe('Graphlib decorations', () => {
|
|||||||
// expect(edgeData.data).toBe('link2');
|
// expect(edgeData.data).toBe('link2');
|
||||||
// expect(validate(g)).toBe(true);
|
// expect(validate(g)).toBe(true);
|
||||||
});
|
});
|
||||||
|
it('adjustClustersAndEdges the extracted graphs shall contain the correct links GLB20', function () {
|
||||||
|
/*
|
||||||
|
a --> b
|
||||||
|
subgraph b [Test]
|
||||||
|
c --> d -->e
|
||||||
|
end
|
||||||
|
*/
|
||||||
|
g.setNode('a', { data: 1 });
|
||||||
|
g.setNode('b', { data: 2 });
|
||||||
|
g.setNode('c', { data: 3 });
|
||||||
|
g.setNode('d', { data: 3 });
|
||||||
|
g.setNode('e', { data: 3 });
|
||||||
|
g.setParent('c', 'b');
|
||||||
|
g.setParent('d', 'b');
|
||||||
|
g.setParent('e', 'b');
|
||||||
|
g.setEdge('a', 'b', { data: 'link1' }, '1');
|
||||||
|
g.setEdge('c', 'd', { data: 'link2' }, '2');
|
||||||
|
g.setEdge('d', 'e', { data: 'link2' }, '2');
|
||||||
|
|
||||||
|
logger.info('Graph before', graphlib.json.write(g))
|
||||||
|
adjustClustersAndEdges(g);
|
||||||
|
const bGraph = g.node('b').graph;
|
||||||
|
// logger.trace('Graph after', graphlib.json.write(g))
|
||||||
|
logger.info('Graph after', graphlib.json.write(bGraph));
|
||||||
|
expect(bGraph.nodes().length).toBe(3);
|
||||||
|
expect(bGraph.edges().length).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('extractDecendants', function () {
|
describe('extractDecendants', function () {
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
import intersect from './intersect/index.js';
|
import intersect from './intersect/index.js';
|
||||||
|
import { select } from 'd3';
|
||||||
import { logger } from '../logger'; // eslint-disable-line
|
import { logger } from '../logger'; // eslint-disable-line
|
||||||
import { labelHelper, updateNodeBounds, insertPolygonShape } from './shapes/util';
|
import { labelHelper, updateNodeBounds, insertPolygonShape } from './shapes/util';
|
||||||
|
import createLabel from './createLabel';
|
||||||
import note from './shapes/note';
|
import note from './shapes/note';
|
||||||
|
|
||||||
const question = (parent, node) => {
|
const question = (parent, node) => {
|
||||||
@@ -253,6 +255,7 @@ const rect = (parent, node) => {
|
|||||||
const rect = shapeSvg.insert('rect', ':first-child');
|
const rect = shapeSvg.insert('rect', ':first-child');
|
||||||
|
|
||||||
rect
|
rect
|
||||||
|
.attr('class', 'basic')
|
||||||
.attr('rx', node.rx)
|
.attr('rx', node.rx)
|
||||||
.attr('ry', node.ry)
|
.attr('ry', node.ry)
|
||||||
.attr('x', -bbox.width / 2 - halfPadding)
|
.attr('x', -bbox.width / 2 - halfPadding)
|
||||||
@@ -268,6 +271,74 @@ const rect = (parent, node) => {
|
|||||||
|
|
||||||
return shapeSvg;
|
return shapeSvg;
|
||||||
};
|
};
|
||||||
|
const rectWithTitle = (parent, node) => {
|
||||||
|
// const { shapeSvg, bbox, halfPadding } = labelHelper(parent, node, 'node ' + node.classes);
|
||||||
|
|
||||||
|
let classes;
|
||||||
|
if (!node.classes) {
|
||||||
|
classes = 'node default';
|
||||||
|
} else {
|
||||||
|
classes = 'node ' + node.classes;
|
||||||
|
}
|
||||||
|
// Add outer g element
|
||||||
|
const shapeSvg = parent
|
||||||
|
.insert('g')
|
||||||
|
.attr('class', classes)
|
||||||
|
.attr('id', node.id);
|
||||||
|
|
||||||
|
// Create the title label and insert it after the rect
|
||||||
|
const rect = shapeSvg.insert('rect', ':first-child');
|
||||||
|
// const innerRect = shapeSvg.insert('rect');
|
||||||
|
const innerLine = shapeSvg.insert('line');
|
||||||
|
|
||||||
|
const label = shapeSvg.insert('g').attr('class', 'label');
|
||||||
|
|
||||||
|
const text2 = node.labelText.flat();
|
||||||
|
logger.info('Label text', text2[0]);
|
||||||
|
|
||||||
|
const text = label.node().appendChild(createLabel(text2[0], node.labelStyle, true));
|
||||||
|
const textRows = text2.slice(1, text2.length);
|
||||||
|
let titleBox = text.getBBox();
|
||||||
|
const descr = label
|
||||||
|
.node()
|
||||||
|
.appendChild(createLabel(textRows.join('<br/>'), node.labelStyle, true));
|
||||||
|
|
||||||
|
logger.info(descr);
|
||||||
|
const halfPadding = node.padding / 2;
|
||||||
|
select(descr).attr('transform', 'translate( 0' + ', ' + (titleBox.height + halfPadding) + ')');
|
||||||
|
// Get the size of the label
|
||||||
|
|
||||||
|
// Bounding box for title and text
|
||||||
|
const bbox = label.node().getBBox();
|
||||||
|
|
||||||
|
// Center the label
|
||||||
|
label.attr(
|
||||||
|
'transform',
|
||||||
|
'translate(' + -bbox.width / 2 + ', ' + (-bbox.height / 2 - halfPadding + 3) + ')'
|
||||||
|
);
|
||||||
|
|
||||||
|
rect
|
||||||
|
.attr('class', 'outer title-state')
|
||||||
|
.attr('x', -bbox.width / 2 - halfPadding)
|
||||||
|
.attr('y', -bbox.height / 2 - halfPadding)
|
||||||
|
.attr('width', bbox.width + node.padding)
|
||||||
|
.attr('height', bbox.height + node.padding);
|
||||||
|
|
||||||
|
innerLine
|
||||||
|
.attr('class', 'divider')
|
||||||
|
.attr('x1', -bbox.width / 2 - halfPadding)
|
||||||
|
.attr('x2', bbox.width / 2 + halfPadding)
|
||||||
|
.attr('y1', -bbox.height / 2 - halfPadding + titleBox.height + halfPadding)
|
||||||
|
.attr('y2', -bbox.height / 2 - halfPadding + titleBox.height + halfPadding);
|
||||||
|
|
||||||
|
updateNodeBounds(node, rect);
|
||||||
|
|
||||||
|
node.intersect = function(point) {
|
||||||
|
return intersect.rect(node, point);
|
||||||
|
};
|
||||||
|
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
||||||
|
|
||||||
const stadium = (parent, node) => {
|
const stadium = (parent, node) => {
|
||||||
const { shapeSvg, bbox } = labelHelper(parent, node);
|
const { shapeSvg, bbox } = labelHelper(parent, node);
|
||||||
@@ -335,6 +406,41 @@ const start = (parent, node) => {
|
|||||||
|
|
||||||
return shapeSvg;
|
return shapeSvg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const forkJoin = (parent, node, dir) => {
|
||||||
|
const shapeSvg = parent
|
||||||
|
.insert('g')
|
||||||
|
.attr('class', 'node default')
|
||||||
|
.attr('id', node.id);
|
||||||
|
|
||||||
|
let width = 70;
|
||||||
|
let height = 10;
|
||||||
|
|
||||||
|
if (dir === 'LR') {
|
||||||
|
width = 10;
|
||||||
|
height = 70;
|
||||||
|
}
|
||||||
|
|
||||||
|
const shape = shapeSvg
|
||||||
|
.append('rect')
|
||||||
|
.style('stroke', 'black')
|
||||||
|
.style('fill', 'black')
|
||||||
|
.attr('x', (-1 * width) / 2)
|
||||||
|
.attr('y', (-1 * height) / 2)
|
||||||
|
.attr('width', width)
|
||||||
|
.attr('height', height)
|
||||||
|
.attr('class', 'fork-join');
|
||||||
|
|
||||||
|
updateNodeBounds(node, shape);
|
||||||
|
node.height = node.height + node.padding / 2;
|
||||||
|
node.width = node.width + node.padding / 2;
|
||||||
|
node.intersect = function(point) {
|
||||||
|
return intersect.rect(node, point);
|
||||||
|
};
|
||||||
|
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
||||||
|
|
||||||
const end = (parent, node) => {
|
const end = (parent, node) => {
|
||||||
const shapeSvg = parent
|
const shapeSvg = parent
|
||||||
.insert('g')
|
.insert('g')
|
||||||
@@ -367,6 +473,7 @@ const end = (parent, node) => {
|
|||||||
const shapes = {
|
const shapes = {
|
||||||
question,
|
question,
|
||||||
rect,
|
rect,
|
||||||
|
rectWithTitle,
|
||||||
circle,
|
circle,
|
||||||
stadium,
|
stadium,
|
||||||
hexagon,
|
hexagon,
|
||||||
@@ -379,13 +486,15 @@ const shapes = {
|
|||||||
cylinder,
|
cylinder,
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
note
|
note,
|
||||||
|
fork: forkJoin,
|
||||||
|
join: forkJoin
|
||||||
};
|
};
|
||||||
|
|
||||||
let nodeElems = {};
|
let nodeElems = {};
|
||||||
|
|
||||||
export const insertNode = (elem, node) => {
|
export const insertNode = (elem, node, dir) => {
|
||||||
nodeElems[node.id] = shapes[node.shape](elem, node);
|
nodeElems[node.id] = shapes[node.shape](elem, node, dir);
|
||||||
};
|
};
|
||||||
export const setNodeElem = (elem, node) => {
|
export const setNodeElem = (elem, node) => {
|
||||||
nodeElems[node.id] = elem;
|
nodeElems[node.id] = elem;
|
||||||
|
54
src/dagre-wrapper/patterns.js
Normal file
54
src/dagre-wrapper/patterns.js
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/**
|
||||||
|
* Setup arrow head and define the marker. The result is appended to the svg.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// import { logger } from '../logger';
|
||||||
|
|
||||||
|
// Only add the number of markers that the diagram needs
|
||||||
|
const insertPatterns = (elem, patternArray, type, id) => {
|
||||||
|
patternArray.forEach(patternName => {
|
||||||
|
patterns[patternName](elem, type, id);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
/* <svg height="10" width="10" xmlns="http://www.w3.org/2000/svg" version="1.1">
|
||||||
|
{' '}
|
||||||
|
<defs>
|
||||||
|
{' '}
|
||||||
|
<pattern id="circles-1" patternUnits="userSpaceOnUse" width="10" height="10">
|
||||||
|
{' '}
|
||||||
|
<image
|
||||||
|
xlink:href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMCcgaGVpZ2h0PScxMCc+CiAgPHJlY3Qgd2lkdGg9JzEwJyBoZWlnaHQ9JzEwJyBmaWxsPSJ3aGl0ZSIgLz4KICA8Y2lyY2xlIGN4PSIxIiBjeT0iMSIgcj0iMSIgZmlsbD0iYmxhY2siLz4KPC9zdmc+"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="10"
|
||||||
|
height="10"
|
||||||
|
>
|
||||||
|
{' '}
|
||||||
|
</image>{' '}
|
||||||
|
</pattern>{' '}
|
||||||
|
</defs>{' '}
|
||||||
|
</svg>; */
|
||||||
|
}
|
||||||
|
|
||||||
|
const dots = (elem, type) => {
|
||||||
|
elem
|
||||||
|
.append('defs')
|
||||||
|
.append('marker')
|
||||||
|
.attr('id', type + '-barbEnd')
|
||||||
|
.attr('refX', 19)
|
||||||
|
.attr('refY', 7)
|
||||||
|
.attr('markerWidth', 20)
|
||||||
|
.attr('markerHeight', 14)
|
||||||
|
.attr('markerUnits', 0)
|
||||||
|
.attr('orient', 'auto')
|
||||||
|
.append('path')
|
||||||
|
.attr('d', 'M 19,7 L9,13 L14,7 L9,1 Z');
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO rename the class diagram markers to something shape descriptive and semanitc free
|
||||||
|
const patterns = {
|
||||||
|
dots
|
||||||
|
};
|
||||||
|
export default insertPatterns;
|
@@ -132,6 +132,7 @@ export const addState = function(id, type, doc, descr, note) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (descr) {
|
if (descr) {
|
||||||
|
logger.info('Adding state ', id, descr);
|
||||||
if (typeof descr === 'string') addDescription(id, descr.trim());
|
if (typeof descr === 'string') addDescription(id, descr.trim());
|
||||||
|
|
||||||
if (typeof descr === 'object') {
|
if (typeof descr === 'object') {
|
||||||
|
@@ -42,6 +42,9 @@ const setupNode = (g, parent, node, altFlag) => {
|
|||||||
if (node.start === false) {
|
if (node.start === false) {
|
||||||
shape = 'end';
|
shape = 'end';
|
||||||
}
|
}
|
||||||
|
if (node.type !== 'default') {
|
||||||
|
shape = node.type;
|
||||||
|
}
|
||||||
|
|
||||||
if (!nodeDb[node.id]) {
|
if (!nodeDb[node.id]) {
|
||||||
nodeDb[node.id] = {
|
nodeDb[node.id] = {
|
||||||
@@ -52,9 +55,27 @@ const setupNode = (g, parent, node, altFlag) => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Description
|
// Build of the array of description strings accordinging
|
||||||
if (node.description) {
|
if (node.description) {
|
||||||
nodeDb[node.id].description = node.description;
|
if (Array.isArray(nodeDb[node.id].description)) {
|
||||||
|
// There already is an array of strings,add to it
|
||||||
|
nodeDb[node.id].shape = 'rectWithTitle';
|
||||||
|
nodeDb[node.id].description.push(node.description);
|
||||||
|
} else {
|
||||||
|
if (nodeDb[node.id].description.length > 0) {
|
||||||
|
// if there is a description already transformit to an array
|
||||||
|
nodeDb[node.id].shape = 'rectWithTitle';
|
||||||
|
if (nodeDb[node.id].description === node.id) {
|
||||||
|
// If the previous description was the is, remove it
|
||||||
|
nodeDb[node.id].description = [node.description];
|
||||||
|
} else {
|
||||||
|
nodeDb[node.id].description = [nodeDb[node.id].description, node.description];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nodeDb[node.id].shape = 'rect';
|
||||||
|
nodeDb[node.id].description = node.description;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save data for description and group so that for instance a statement without description overwrites
|
// Save data for description and group so that for instance a statement without description overwrites
|
||||||
@@ -64,7 +85,7 @@ const setupNode = (g, parent, node, altFlag) => {
|
|||||||
if (!nodeDb[node.id].type && node.doc) {
|
if (!nodeDb[node.id].type && node.doc) {
|
||||||
logger.info('Setting cluser for ', node.id);
|
logger.info('Setting cluser for ', node.id);
|
||||||
nodeDb[node.id].type = 'group';
|
nodeDb[node.id].type = 'group';
|
||||||
nodeDb[node.id].shape = 'roundedWithTitle';
|
nodeDb[node.id].shape = node.type === 'divider' ? 'divider' : 'roundedWithTitle';
|
||||||
nodeDb[node.id].classes =
|
nodeDb[node.id].classes =
|
||||||
nodeDb[node.id].classes +
|
nodeDb[node.id].classes +
|
||||||
' ' +
|
' ' +
|
||||||
@@ -155,10 +176,12 @@ const setupDoc = (g, parent, doc, altFlag) => {
|
|||||||
setupNode(g, parent, item.state1, altFlag);
|
setupNode(g, parent, item.state1, altFlag);
|
||||||
setupNode(g, parent, item.state2, altFlag);
|
setupNode(g, parent, item.state2, altFlag);
|
||||||
const edgeData = {
|
const edgeData = {
|
||||||
|
id: 'edge' + cnt,
|
||||||
arrowhead: 'normal',
|
arrowhead: 'normal',
|
||||||
arrowType: 'arrow_barb',
|
arrowType: 'arrow_barb',
|
||||||
style: 'fill:none',
|
style: 'fill:none',
|
||||||
labelStyle: '',
|
labelStyle: '',
|
||||||
|
label: item.description,
|
||||||
arrowheadStyle: 'fill: #333',
|
arrowheadStyle: 'fill: #333',
|
||||||
labelpos: 'c',
|
labelpos: 'c',
|
||||||
labelType: 'text'
|
labelType: 'text'
|
||||||
|
@@ -36,6 +36,9 @@
|
|||||||
|
|
||||||
.edgeLabel {
|
.edgeLabel {
|
||||||
background-color: $edgeLabelBackground;
|
background-color: $edgeLabelBackground;
|
||||||
|
rect {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -85,6 +85,16 @@ g.stateGroup line {
|
|||||||
fill: $nodeBkg;
|
fill: $nodeBkg;
|
||||||
stroke: $nodeBorder;
|
stroke: $nodeBorder;
|
||||||
stroke-width: 1px;
|
stroke-width: 1px;
|
||||||
|
}
|
||||||
|
.statediagram-cluster rect.outer {
|
||||||
|
rx: 5px;
|
||||||
|
ry: 5px;
|
||||||
|
}
|
||||||
|
.statediagram-state .divider {
|
||||||
|
stroke: $nodeBorder;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statediagram-state .title-state {
|
||||||
rx: 5px;
|
rx: 5px;
|
||||||
ry: 5px;
|
ry: 5px;
|
||||||
}
|
}
|
||||||
@@ -100,10 +110,14 @@ g.stateGroup line {
|
|||||||
ry:0;
|
ry:0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.statediagram-state rect {
|
.statediagram-state rect.basic {
|
||||||
rx: 5px;
|
rx: 5px;
|
||||||
ry: 5px;
|
ry: 5px;
|
||||||
}
|
}
|
||||||
|
.statediagram-state rect.divider {
|
||||||
|
stroke-dasharray: 10,10;
|
||||||
|
fill: #efefef;
|
||||||
|
}
|
||||||
|
|
||||||
.note-edge {
|
.note-edge {
|
||||||
stroke-dasharray: 5;
|
stroke-dasharray: 5;
|
||||||
|
Reference in New Issue
Block a user