mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-28 07:03:17 +08:00
Merge remote-tracking branch 'origin/release/9.1.4'
This commit is contained in:
commit
b7925936f8
2
.github/workflows/checks.yml
vendored
2
.github/workflows/checks.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
name: check tests
|
||||
if: github.repository_owner == 'mermaid'
|
||||
if: github.repository_owner == 'mermaid-js'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
|
5
cypress/fixtures/example.json
Normal file
5
cypress/fixtures/example.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io",
|
||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||
}
|
@ -42,7 +42,8 @@ export const imgSnapshotTest = (graphStr, _options, api = false, validation) =>
|
||||
if (!options.fontSize) {
|
||||
options.fontSize = '16px';
|
||||
}
|
||||
const useAppli = Cypress.env('useAppli');
|
||||
// const useAppli = Cypress.env('useAppli');
|
||||
const useAppli = false;
|
||||
const branch = Cypress.env('codeBranch');
|
||||
cy.log('Hello ' + useAppli ? 'Appli' : 'image-snapshot');
|
||||
const name = (options.name || cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
|
||||
|
@ -4,7 +4,7 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body').find('g#flowchart-Function-2').click();
|
||||
cy.get('body').find('g#flowchart-Function-4').click();
|
||||
|
||||
cy.get('.created-by-click').should('have.text', 'Clicked By Flow');
|
||||
});
|
||||
@ -12,7 +12,7 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body').find('g#flowchart-FunctionArg-18').click();
|
||||
cy.get('body').find('g#flowchart-FunctionArg-28').click();
|
||||
|
||||
cy.get('.created-by-click-2').should('have.text', 'Clicked By Flow: ARGUMENT');
|
||||
});
|
||||
@ -20,7 +20,7 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body').find('g[id="flowchart-FunctionArg-22"]').click();
|
||||
cy.get('body').find('g[id="flowchart-FunctionArg-34"]').click();
|
||||
|
||||
cy.get('.created-by-click-2').should('have.text', 'Clicked By Flow: ARGUMENT');
|
||||
});
|
||||
@ -28,7 +28,7 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body').find('#flowchart-URL-3').click();
|
||||
cy.get('body').find('#flowchart-URL-5').click();
|
||||
|
||||
cy.location().should((location) => {
|
||||
expect(location.href).to.eq('http://localhost:9000/webpackUsage.html');
|
||||
@ -38,7 +38,7 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body').find('g[id="flowchart-2URL-7"]').click();
|
||||
cy.get('body').find('g[id="flowchart-2URL-11"]').click();
|
||||
|
||||
cy.location().should((location) => {
|
||||
expect(location.href).to.eq('http://localhost:9000/webpackUsage.html');
|
||||
@ -49,7 +49,7 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body').find('g#flowchart-Function-10').click();
|
||||
cy.get('body').find('g#flowchart-Function-16').click();
|
||||
|
||||
cy.get('.created-by-click').should('have.text', 'Clicked By Flow');
|
||||
});
|
||||
@ -57,7 +57,7 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body').find('g[id="flowchart-1Function-14"]').click();
|
||||
cy.get('body').find('g[id="flowchart-1Function-22"]').click();
|
||||
|
||||
cy.get('.created-by-click').should('have.text', 'Clicked By Flow');
|
||||
});
|
||||
@ -65,7 +65,7 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body').find('#flowchart-URL-11').click();
|
||||
cy.get('body').find('#flowchart-URL-17').click();
|
||||
|
||||
cy.location().should((location) => {
|
||||
expect(location.href).to.eq('http://localhost:9000/webpackUsage.html');
|
||||
@ -75,7 +75,7 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body').find('g[id="flowchart-2URL-15"]').click();
|
||||
cy.get('body').find('g[id="flowchart-2URL-23"]').click();
|
||||
|
||||
cy.location().should((location) => {
|
||||
expect(location.href).to.eq('http://localhost:9000/webpackUsage.html');
|
||||
@ -142,7 +142,7 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_strict.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body').find('g#flowchart-Function-2').click();
|
||||
cy.get('body').find('g#flowchart-Function-4').click();
|
||||
|
||||
cy.get('.created-by-click').should('not.exist');
|
||||
// cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow');
|
||||
@ -151,7 +151,7 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_strict.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body').find('g[id="flowchart-1Function-6"]').click();
|
||||
cy.get('body').find('g[id="flowchart-1Function-10"]').click();
|
||||
|
||||
// cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow');
|
||||
cy.get('.created-by-click').should('not.exist');
|
||||
@ -160,7 +160,7 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_strict.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body').find('g#flowchart-URL-3').click();
|
||||
cy.get('body').find('g#flowchart-URL-5').click();
|
||||
|
||||
cy.location().should((location) => {
|
||||
expect(location.href).to.eq('http://localhost:9000/webpackUsage.html');
|
||||
@ -170,7 +170,7 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_strict.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body').find('g[id="flowchart-2URL-7"]').click();
|
||||
cy.get('body').find('g[id="flowchart-2URL-11"]').click();
|
||||
|
||||
cy.location().should((location) => {
|
||||
expect(location.href).to.eq('http://localhost:9000/webpackUsage.html');
|
||||
@ -222,7 +222,7 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_other.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body').find('g#flowchart-Function-2').click();
|
||||
cy.get('body').find('g#flowchart-Function-4').click();
|
||||
|
||||
// cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow');
|
||||
cy.get('.created-by-click').should('not.exist');
|
||||
@ -231,7 +231,7 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_other.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body').find('g[id="flowchart-1Function-6"]').click();
|
||||
cy.get('body').find('g[id="flowchart-1Function-10"]').click();
|
||||
|
||||
cy.get('.created-by-click').should('not.exist');
|
||||
cy.get('.created-by-click').should('not.exist');
|
||||
@ -240,7 +240,7 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_other.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body').find('g#flowchart-URL-3').click();
|
||||
cy.get('body').find('g#flowchart-URL-5').click();
|
||||
|
||||
cy.location().should((location) => {
|
||||
expect(location.href).to.eq('http://localhost:9000/webpackUsage.html');
|
@ -207,4 +207,50 @@ describe('Git Graph diagram', () => {
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('12: should render commits for more than 8 branches', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
gitGraph
|
||||
checkout main
|
||||
commit
|
||||
checkout main
|
||||
branch branch1
|
||||
commit
|
||||
checkout main
|
||||
merge branch1
|
||||
branch branch2
|
||||
commit
|
||||
checkout main
|
||||
merge branch2
|
||||
branch branch3
|
||||
commit
|
||||
checkout main
|
||||
merge branch3
|
||||
branch branch4
|
||||
commit
|
||||
checkout main
|
||||
merge branch4
|
||||
branch branch5
|
||||
commit
|
||||
checkout main
|
||||
merge branch5
|
||||
branch branch6
|
||||
commit
|
||||
checkout main
|
||||
merge branch6
|
||||
branch branch7
|
||||
commit
|
||||
checkout main
|
||||
merge branch7
|
||||
branch branch8
|
||||
commit
|
||||
checkout main
|
||||
merge branch8
|
||||
branch branch9
|
||||
commit
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
});
|
@ -80,7 +80,7 @@ context('Sequence diagram', () => {
|
||||
loop Loopy
|
||||
Bob->>Alice: Pasten
|
||||
end `,
|
||||
{}
|
||||
{ wrap: true }
|
||||
);
|
||||
});
|
||||
context('font settings', () => {
|
||||
@ -126,6 +126,17 @@ context('Sequence diagram', () => {
|
||||
{ sequence: { noteAlign: 'left' } }
|
||||
);
|
||||
});
|
||||
it('should render multi-line notes aligned to the left when configured', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice->>Bob: I'm short
|
||||
note left of Alice: I am left aligned<br>but also<br>multiline
|
||||
Bob->>Alice: Short as well
|
||||
`,
|
||||
{ sequence: { noteAlign: 'left' } }
|
||||
);
|
||||
});
|
||||
it('should render notes aligned to the right when configured', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
@ -137,6 +148,37 @@ context('Sequence diagram', () => {
|
||||
{ sequence: { noteAlign: 'right' } }
|
||||
);
|
||||
});
|
||||
it('should render multi-line notes aligned to the right when configured', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice->>Bob: I'm short
|
||||
note left of Alice: I am right aligned<br>but also<br>multiline
|
||||
Bob->>Alice: Short as well
|
||||
`,
|
||||
{ sequence: { noteAlign: 'right' } }
|
||||
);
|
||||
});
|
||||
it('should render multi-line messages aligned to the left when configured', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice->>Bob: I'm short<br>but also<br>multiline
|
||||
Bob->>Alice: Short as well<br>and also<br>multiline
|
||||
`,
|
||||
{ sequence: { messageAlign: 'left' } }
|
||||
);
|
||||
});
|
||||
it('should render multi-line messages aligned to the right when configured', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice->>Bob: I'm short<br>but also<br>multiline
|
||||
Bob->>Alice: Short as well<br>and also<br>multiline
|
||||
`,
|
||||
{ sequence: { messageAlign: 'right' } }
|
||||
);
|
||||
});
|
||||
});
|
||||
context('auth width scaling', () => {
|
||||
it('should render long actor descriptions', () => {
|
@ -509,4 +509,16 @@ stateDiagram-v2
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
});
|
||||
|
||||
it('v2 should render a state diagram and set the correct length of the labels', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
stateDiagram-v2
|
||||
[*] --> 1
|
||||
1 --> 2: test({ foo#colon; 'far' })
|
||||
2 --> [*]
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
});
|
@ -31,14 +31,15 @@
|
||||
|
||||
|
||||
<div class="mermaid2" style="width: 50%;">
|
||||
journey
|
||||
title Adding journey diagram functionality to mermaid
|
||||
accTitle: Adding acc journey diagram functionality to mermaid
|
||||
accDescr {
|
||||
My multi-line description
|
||||
of the diagram
|
||||
}
|
||||
section Order from website
|
||||
journey
|
||||
title My working day
|
||||
section Go to work
|
||||
Make tea: 5: Me
|
||||
Go upstairs: 3: Me
|
||||
Do work: 1: Me, Cat
|
||||
section Go home
|
||||
Go downstairs: 5: Me
|
||||
Sit down: 5: Mee
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 50%;">
|
||||
pie
|
||||
@ -52,20 +53,16 @@
|
||||
"Iron" : 5
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 50%;">
|
||||
gitGraph
|
||||
accTitle: My Gitgraph Accessibility Title
|
||||
accDescr: My Gitgraph Accessibility Description
|
||||
|
||||
commit
|
||||
commit
|
||||
branch develop
|
||||
checkout develop
|
||||
commit
|
||||
commit
|
||||
checkout main
|
||||
merge develop
|
||||
commit
|
||||
commit
|
||||
gitGraph
|
||||
commit
|
||||
commit
|
||||
branch develop
|
||||
commit
|
||||
commit
|
||||
commit
|
||||
checkout main
|
||||
commit
|
||||
commit
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 50%;">
|
||||
sequenceDiagram
|
||||
@ -99,6 +96,9 @@ graph TD
|
||||
Sit down: 5: Me
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 100%;">
|
||||
info
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 100%;">
|
||||
requirementDiagram
|
||||
accTitle: My req Diagram
|
||||
accDescr: My req Diagram Description
|
||||
@ -138,8 +138,41 @@ requirementDiagram
|
||||
test_req - traces -> test_req2
|
||||
test_req - contains -> test_req3
|
||||
test_req <- copies - test_entity2
|
||||
|
||||
</div>
|
||||
<div class="mermaid" style="width: 100%;">
|
||||
<div class="mermaid2" style="width: 100%;">
|
||||
gantt
|
||||
dateFormat YYYY-MM-DD
|
||||
title Adding GANTT diagram functionality to mermaid
|
||||
excludes weekends
|
||||
%% (`excludes` accepts specific dates in YYYY-MM-DD format, days of the week ("sunday") or "weekends", but not the word "weekdays".)
|
||||
|
||||
section A section
|
||||
Completed task :done, des1, 2014-01-06,2014-01-08
|
||||
Active task :active, des2, 2014-01-09, 3d
|
||||
Future task : des3, after des2, 5d
|
||||
Future task2 : des4, after des3, 5d
|
||||
|
||||
section Critical tasks
|
||||
Completed task in the critical line :crit, done, 2014-01-06,24h
|
||||
Implement parser and jison :crit, done, after des1, 2d
|
||||
Create tests for parser :crit, active, 3d
|
||||
Future task in critical line :crit, 5d
|
||||
Create tests for renderer :2d
|
||||
Add to mermaid :1d
|
||||
Functionality added :milestone, 2014-01-25, 0d
|
||||
|
||||
section Documentation
|
||||
Describe gantt syntax :active, a1, after des1, 3d
|
||||
Add gantt diagram to demo page :after a1 , 20h
|
||||
Add another diagram to demo page :doc1, after a1 , 48h
|
||||
|
||||
section Last section
|
||||
Describe gantt syntax :after doc1, 3d
|
||||
Add gantt diagram to demo page :20h
|
||||
Add another diagram to demo page :48h
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 100%;">
|
||||
stateDiagram
|
||||
state Active {
|
||||
Idle
|
||||
@ -148,7 +181,7 @@ stateDiagram
|
||||
Active --> Active: LOG
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 100%;">
|
||||
graph TB
|
||||
flowchart TB
|
||||
accTitle: My flowchart
|
||||
accDescr: My flowchart Description
|
||||
subgraph One
|
||||
@ -165,8 +198,7 @@ stateDiagram
|
||||
end
|
||||
end
|
||||
end
|
||||
B ->> A: Return
|
||||
</div>
|
||||
B ->> A: Return</div>
|
||||
<div class="mermaid2" style="width: 100%;">
|
||||
classDiagram
|
||||
accTitle: My class diagram
|
||||
@ -185,14 +217,42 @@ class Class10 {
|
||||
size()
|
||||
}
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 100%;">
|
||||
stateDiagram
|
||||
accTitle: Apa
|
||||
accDescr: One that can climb better then any man
|
||||
[*] --> S1
|
||||
state "Some long name" as S1
|
||||
<div class="mermaid" style="width: 100%;">
|
||||
%%{init: {'config': {'wrap': true }}}%%
|
||||
sequenceDiagram
|
||||
participant A as Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||
A->>Bob: Hola
|
||||
Bob-->A: Pasten !
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 100%;">
|
||||
gitGraph
|
||||
commit id: "ZERO"
|
||||
branch develop
|
||||
commit id:"A"
|
||||
checkout main
|
||||
commit id:"ONE"
|
||||
checkout develop
|
||||
commit id:"B"
|
||||
branch featureA
|
||||
commit id:"FIX"
|
||||
commit id: "FIX-2"
|
||||
checkout main
|
||||
commit id:"TWO"
|
||||
cherry-pick id:"A"
|
||||
commit id:"THREE"
|
||||
cherry-pick id:"FIX"
|
||||
checkout develop
|
||||
commit id:"C"
|
||||
merge featureA
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 100%;">
|
||||
flowchart TD
|
||||
A[Christmas] -->|Get money| B(Go shopping)
|
||||
B --> C{Let me think}
|
||||
C -->|One| D[Laptop]
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
</div> <div class="mermaid2" style="width: 100%;">
|
||||
classDiagram
|
||||
Animal "1" <|-- Duck
|
||||
Animal <|-- Fish
|
||||
@ -215,6 +275,21 @@ class Class10 {
|
||||
+run()
|
||||
}
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 100%;">
|
||||
erDiagram
|
||||
CAR ||--o{ NAMED-DRIVER : allows
|
||||
CAR {
|
||||
string registrationNumber
|
||||
string make
|
||||
string model
|
||||
}
|
||||
PERSON ||--o{ NAMED-DRIVER : is
|
||||
PERSON {
|
||||
string firstName
|
||||
string lastName
|
||||
int age
|
||||
}
|
||||
</div>
|
||||
|
||||
<script src="./mermaid.js"></script>
|
||||
<script>
|
||||
@ -236,6 +311,10 @@ class Class10 {
|
||||
class: {
|
||||
// defaultRenderer: 'dagre-d3',
|
||||
htmlLabels: true,
|
||||
},
|
||||
sequence: {
|
||||
// mirrorActors: false,'
|
||||
wrap: false,
|
||||
},
|
||||
// gantt: { axisFormat: '%m/%d/%Y' },
|
||||
// sequence: {
|
||||
@ -251,12 +330,14 @@ class Class10 {
|
||||
state: {
|
||||
nodeSpacing: 50,
|
||||
rankSpacing: 50,
|
||||
defaultRenderer: 'dagre-d3',
|
||||
},
|
||||
logLevel: 0,
|
||||
fontSize: 18,
|
||||
curve: 'cardinal',
|
||||
// securityLevel: 'sandbox',
|
||||
// themeVariables: {relationLabelColor: 'red'}
|
||||
wrap: true,
|
||||
});
|
||||
function callback() {
|
||||
alert('It worked');
|
||||
|
32
cypress/plugins/index.js
Normal file
32
cypress/plugins/index.js
Normal file
@ -0,0 +1,32 @@
|
||||
// ***********************************************************
|
||||
// This example plugins/index.js can be used to load plugins
|
||||
//
|
||||
// You can change the location of this file or turn off loading
|
||||
// the plugins file with the 'pluginsFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/plugins-guide
|
||||
// ***********************************************************
|
||||
|
||||
// This function is called when a project is opened or re-opened (e.g. due to
|
||||
// the project's config changing)
|
||||
|
||||
// module.exports = (on, config) => {
|
||||
// // `on` is used to hook into various events Cypress emits
|
||||
// // `config` is the resolved Cypress config
|
||||
// }
|
||||
|
||||
const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin');
|
||||
require('@applitools/eyes-cypress')(module);
|
||||
|
||||
module.exports = (on, config) => {
|
||||
addMatchImageSnapshotPlugin(on, config);
|
||||
// copy any needed variables from process.env to config.env
|
||||
config.env.useAppli = process.env.USE_APPLI ? true : false;
|
||||
config.env.codeBranch = process.env.APPLI_BRANCH;
|
||||
|
||||
// do not forget to return the changed config object!
|
||||
return config;
|
||||
};
|
||||
|
||||
require('@applitools/eyes-cypress')(module);
|
@ -27,10 +27,11 @@ But not having diagrams or docs ruins productivity and hurts organizational lear
|
||||
Mermaid addresses this problem by enabling users to create easily modifiable diagrams, it can also be made part of production scripts (and other pieces of code).<br/>
|
||||
<br/>
|
||||
Mermaid allows even non-programmers to easily create detailed and diagrams through the [Mermaid Live Editor](https://mermaid.live/).<br/>
|
||||
[Tutorials](./docs/Tutorials.md) has video tutorials.
|
||||
Use Mermaid with your favorite applications, check out the list of [Integrations and Usages of Mermaid](./docs/integrations.md).
|
||||
[Tutorials](./Tutorials.md) has video tutorials.
|
||||
Use Mermaid with your favorite applications, check out the list of [Integrations and Usages of Mermaid](./integrations.md).
|
||||
|
||||
For a more detailed introduction to Mermaid and some of its more basic uses, look to the [Beginner's Guide](./docs/n00b-overview.md) and [Usage](./docs/usage.md).
|
||||
|
||||
For a more detailed introduction to Mermaid and some of its more basic uses, look to the [Beginner's Guide](./n00b-overview.md) and [Usage](./usage.md).
|
||||
|
||||
🌐 [CDN](https://unpkg.com/mermaid/) | 📖 [Documentation](https://mermaidjs.github.io) | 🙌 [Contribution](https://github.com/mermaid-js/mermaid/blob/develop/docs/development.md) | 📜 [Version Log](./CHANGELOG.md) | 🔌 [Plug-Ins](./integrations.md)
|
||||
|
||||
|
@ -1401,6 +1401,15 @@ This sets the auto-wrap padding for the diagram (sides only)
|
||||
|
||||
**Notes:** Default value: 0.
|
||||
|
||||
## parse
|
||||
|
||||
### Parameters
|
||||
|
||||
- `text`
|
||||
- `dia`
|
||||
|
||||
Returns **any**
|
||||
|
||||
## setSiteConfig
|
||||
|
||||
## setSiteConfig
|
||||
@ -1420,14 +1429,6 @@ function _Default value: At default, will mirror Global Config_
|
||||
|
||||
Returns **[object][5]** The siteConfig
|
||||
|
||||
## parse
|
||||
|
||||
### Parameters
|
||||
|
||||
- `text`
|
||||
|
||||
Returns **any**
|
||||
|
||||
## getSiteConfig
|
||||
|
||||
## getSiteConfig
|
||||
@ -1470,6 +1471,34 @@ Returns **any** The currentConfig merged with the sanitized conf
|
||||
|
||||
Returns **any** The currentConfig
|
||||
|
||||
## render
|
||||
|
||||
Function that renders an svg with a graph from a chart definition. Usage example below.
|
||||
|
||||
```javascript
|
||||
mermaidAPI.initialize({
|
||||
startOnLoad: true,
|
||||
});
|
||||
$(function () {
|
||||
const graphDefinition = 'graph TB\na-->b';
|
||||
const cb = function (svgGraph) {
|
||||
console.log(svgGraph);
|
||||
};
|
||||
mermaidAPI.render('id1', graphDefinition, cb);
|
||||
});
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
- `id` **any** The id of the element to be rendered
|
||||
- `_txt` **any** The graph definition
|
||||
- `cb` **any** Callback which is called after rendering is finished with the svg code as inparam.
|
||||
- `container` **any** Selector to element in which a div with the graph temporarily will be
|
||||
inserted. In one is provided a hidden div will be inserted in the body of the page instead. The
|
||||
element will be removed when rendering is completed.
|
||||
|
||||
Returns **any**
|
||||
|
||||
## sanitize
|
||||
|
||||
## sanitize
|
||||
@ -1509,44 +1538,12 @@ Pushes in a directive to the configuration
|
||||
|
||||
**Notes**: (default: current siteConfig ) (optional, default `getSiteConfig()`)
|
||||
|
||||
## render
|
||||
|
||||
Function that renders an svg with a graph from a chart definition. Usage example below.
|
||||
|
||||
```javascript
|
||||
mermaidAPI.initialize({
|
||||
startOnLoad: true,
|
||||
});
|
||||
$(function () {
|
||||
const graphDefinition = 'graph TB\na-->b';
|
||||
const cb = function (svgGraph) {
|
||||
console.log(svgGraph);
|
||||
};
|
||||
mermaidAPI.render('id1', graphDefinition, cb);
|
||||
});
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
- `id` **any** The id of the element to be rendered
|
||||
- `_txt` **any** The graph definition
|
||||
- `cb` **any** Callback which is called after rendering is finished with the svg code as inparam.
|
||||
- `container` **any** Selector to element in which a div with the graph temporarily will be
|
||||
inserted. In one is provided a hidden div will be inserted in the body of the page instead. The
|
||||
element will be removed when rendering is completed.
|
||||
|
||||
Returns **any**
|
||||
|
||||
## updateRendererConfigs
|
||||
|
||||
### Parameters
|
||||
|
||||
- `conf` **any**
|
||||
|
||||
## reinitialize
|
||||
|
||||
To be removed
|
||||
|
||||
## initialize
|
||||
|
||||
### Parameters
|
||||
|
@ -260,7 +260,7 @@ UpdateRelStyle(customerA, bankA, $offsetY="60")
|
||||
System_Ext(mbs, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.")
|
||||
|
||||
Container_Boundary(api, "API Application") {
|
||||
Component(sign, "Sign In Controller", "MVC Rest Controlle", "Allows users to sign in to the internet banking system")
|
||||
Component(sign, "Sign In Controller", "MVC Rest Controller", "Allows users to sign in to the internet banking system")
|
||||
Component(accounts, "Accounts Summary Controller", "MVC Rest Controller", "Provides customers with a summary of their bank accounts")
|
||||
Component(security, "Security Component", "Spring Bean", "Provides functionality related to singing in, changing passwords, etc.")
|
||||
Component(mbsfacade, "Mainframe Banking System Facade", "Spring Bean", "A facade onto the mainframe banking system.")
|
||||
@ -364,4 +364,4 @@ UpdateRelStyle(customerA, bankA, $offsetY="60")
|
||||
UpdateRelStyle(api, db2, $offsetX="-40", $offsetY="-20")
|
||||
UpdateRelStyle(db, db2, $offsetY="-10")
|
||||
|
||||
```
|
||||
```
|
||||
|
@ -612,12 +612,14 @@ The icons are accessed via the syntax fa:#icon class name#.
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
B["fa:fa-twitter for peace"]
|
||||
B["fab:fa-twitter for peace"]
|
||||
B-->C[fa:fa-ban forbidden]
|
||||
B-->D(fa:fa-spinner);
|
||||
B-->E(A fa:fa-camera-retro perhaps?)
|
||||
```
|
||||
|
||||
?> Mermaid is now only compatible with Font Awesome versions 4 and 5. Check that you are using the correct version of Font Awesome.
|
||||
|
||||
|
||||
## Graph declarations with spaces between vertices and link and without semicolon
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
/>
|
||||
<!-- <link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css"> -->
|
||||
<link rel="stylesheet" href="theme.css" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.min.css">
|
||||
<script src="//cdn.jsdelivr.net/npm/mermaid@9.1.3/dist/mermaid.min.js"></script>
|
||||
<!-- <script src="http://localhost:9000/mermaid.js"></script> -->
|
||||
<script>
|
||||
|
@ -249,3 +249,13 @@ stateDiagram-v2
|
||||
## Styling
|
||||
|
||||
Styling of the a state diagram is done by defining a number of css classes. During rendering these classes are extracted from the file located at src/themes/state.scss
|
||||
|
||||
## Spaces in state names
|
||||
|
||||
Spaces can be added to a state by defining it at the top and referencing the acronym later.
|
||||
|
||||
```mermaid-example
|
||||
stateDiagram-v2
|
||||
Yswsii: Your state with spaces in it
|
||||
[*] --> Yswsii
|
||||
```
|
||||
|
12
package.json
12
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mermaid",
|
||||
"version": "9.1.3",
|
||||
"version": "9.1.4",
|
||||
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
|
||||
"main": "dist/mermaid.core.js",
|
||||
"module": "dist/mermaid.esm.min.mjs",
|
||||
@ -27,7 +27,7 @@
|
||||
"postbuild": "documentation build src/mermaidAPI.js src/config.js src/defaultConfig.js --shallow -f md --markdown-toc false > docs/Setup.md",
|
||||
"build:watch": "yarn build:development --watch",
|
||||
"release": "yarn build",
|
||||
"lint": "eslint ./ --ext .js,.json,.html,.md",
|
||||
"lint": "eslint ./ --ext .js,.json,.html",
|
||||
"lint:fix": "yarn lint --fix",
|
||||
"e2e:depr": "yarn lint && jest e2e --config e2e/jest.config.js",
|
||||
"cypress": "cypress run",
|
||||
@ -62,7 +62,7 @@
|
||||
"d3": "^7.0.0",
|
||||
"dagre": "^0.8.5",
|
||||
"dagre-d3": "^0.6.4",
|
||||
"dompurify": "2.3.8",
|
||||
"dompurify": "2.3.10",
|
||||
"graphlib": "^2.1.8",
|
||||
"khroma": "^2.0.0",
|
||||
"moment-mini": "^2.24.0",
|
||||
@ -81,17 +81,17 @@
|
||||
"concurrently": "^7.0.0",
|
||||
"coveralls": "^3.0.2",
|
||||
"css-to-string-loader": "^0.1.3",
|
||||
"cypress": "10.2.0",
|
||||
"cypress": "9.7.0",
|
||||
"cypress-image-snapshot": "^4.0.1",
|
||||
"documentation": "13.2.0",
|
||||
"eslint": "^8.4.1",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-cypress": "^2.12.1",
|
||||
"eslint-plugin-html": "^6.2.0",
|
||||
"eslint-plugin-html": "^7.1.0",
|
||||
"eslint-plugin-jest": "^26.0.0",
|
||||
"eslint-plugin-jsdoc": "^39.1.0",
|
||||
"eslint-plugin-json": "^3.1.0",
|
||||
"eslint-plugin-markdown": "^2.2.1",
|
||||
"eslint-plugin-markdown": "^3.0.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"husky": "^8.0.0",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
|
189
src/Diagram.js
189
src/Diagram.js
@ -1,166 +1,65 @@
|
||||
import c4Db from './diagrams/c4/c4Db';
|
||||
import c4Renderer from './diagrams/c4/c4Renderer';
|
||||
import c4Parser from './diagrams/c4/parser/c4Diagram';
|
||||
import classDb from './diagrams/class/classDb';
|
||||
import classRenderer from './diagrams/class/classRenderer';
|
||||
import classRendererV2 from './diagrams/class/classRenderer-v2';
|
||||
import classParser from './diagrams/class/parser/classDiagram';
|
||||
import erDb from './diagrams/er/erDb';
|
||||
import erRenderer from './diagrams/er/erRenderer';
|
||||
import erParser from './diagrams/er/parser/erDiagram';
|
||||
import flowDb from './diagrams/flowchart/flowDb';
|
||||
import flowRenderer from './diagrams/flowchart/flowRenderer';
|
||||
import flowRendererV2 from './diagrams/flowchart/flowRenderer-v2';
|
||||
import flowParser from './diagrams/flowchart/parser/flow';
|
||||
import ganttDb from './diagrams/gantt/ganttDb';
|
||||
import ganttRenderer from './diagrams/gantt/ganttRenderer';
|
||||
import ganttParser from './diagrams/gantt/parser/gantt';
|
||||
import gitGraphAst from './diagrams/git/gitGraphAst';
|
||||
import gitGraphRenderer from './diagrams/git/gitGraphRenderer';
|
||||
import gitGraphParser from './diagrams/git/parser/gitGraph';
|
||||
import infoDb from './diagrams/info/infoDb';
|
||||
import infoRenderer from './diagrams/info/infoRenderer';
|
||||
import infoParser from './diagrams/info/parser/info';
|
||||
import pieParser from './diagrams/pie/parser/pie';
|
||||
import pieDb from './diagrams/pie/pieDb';
|
||||
import pieRenderer from './diagrams/pie/pieRenderer';
|
||||
import requirementParser from './diagrams/requirement/parser/requirementDiagram';
|
||||
import requirementDb from './diagrams/requirement/requirementDb';
|
||||
import requirementRenderer from './diagrams/requirement/requirementRenderer';
|
||||
import sequenceParser from './diagrams/sequence/parser/sequenceDiagram';
|
||||
import sequenceDb from './diagrams/sequence/sequenceDb';
|
||||
import sequenceRenderer from './diagrams/sequence/sequenceRenderer';
|
||||
import stateParser from './diagrams/state/parser/stateDiagram';
|
||||
import stateDb from './diagrams/state/stateDb';
|
||||
import stateRenderer from './diagrams/state/stateRenderer';
|
||||
import stateRendererV2 from './diagrams/state/stateRenderer-v2';
|
||||
import journeyDb from './diagrams/user-journey/journeyDb';
|
||||
import journeyRenderer from './diagrams/user-journey/journeyRenderer';
|
||||
import journeyParser from './diagrams/user-journey/parser/journey';
|
||||
import utils from './utils';
|
||||
import * as configApi from './config';
|
||||
import { log } from './logger';
|
||||
|
||||
import { getDiagrams } from './diagram-api/diagramAPI';
|
||||
import detectType from './diagram-api/detectType';
|
||||
class Diagram {
|
||||
type = 'graph';
|
||||
parser;
|
||||
renderer;
|
||||
db;
|
||||
constructor(txt) {
|
||||
const diagrams = getDiagrams();
|
||||
const cnf = configApi.getConfig();
|
||||
this.txt = txt;
|
||||
this.type = utils.detectType(txt, cnf);
|
||||
this.type = detectType(txt, cnf);
|
||||
log.debug('Type ' + this.type);
|
||||
switch (this.type) {
|
||||
case 'c4':
|
||||
this.parser = c4Parser;
|
||||
this.parser.parser.yy = c4Db;
|
||||
this.db = c4Db;
|
||||
this.renderer = c4Renderer;
|
||||
break;
|
||||
case 'gitGraph':
|
||||
this.parser = gitGraphParser;
|
||||
this.parser.parser.yy = gitGraphAst;
|
||||
this.db = gitGraphAst;
|
||||
this.renderer = gitGraphRenderer;
|
||||
break;
|
||||
case 'flowchart':
|
||||
flowDb.clear();
|
||||
this.parser = flowParser;
|
||||
this.parser.parser.yy = flowDb;
|
||||
this.db = flowDb;
|
||||
this.renderer = flowRenderer;
|
||||
break;
|
||||
case 'flowchart-v2':
|
||||
flowDb.clear();
|
||||
this.parser = flowParser;
|
||||
this.parser.parser.yy = flowDb;
|
||||
this.db = flowDb;
|
||||
this.renderer = flowRendererV2;
|
||||
break;
|
||||
case 'sequenceDiagram':
|
||||
case 'sequence':
|
||||
this.parser = sequenceParser;
|
||||
this.parser.parser.yy = sequenceDb;
|
||||
this.db = sequenceDb;
|
||||
this.renderer = sequenceRenderer;
|
||||
break;
|
||||
case 'gantt':
|
||||
this.parser = ganttParser;
|
||||
this.parser.parser.yy = ganttDb;
|
||||
this.db = ganttDb;
|
||||
this.renderer = ganttRenderer;
|
||||
break;
|
||||
case 'class':
|
||||
this.parser = classParser;
|
||||
this.parser.parser.yy = classDb;
|
||||
this.db = classDb;
|
||||
this.renderer = classRenderer;
|
||||
break;
|
||||
case 'classDiagram':
|
||||
this.parser = classParser;
|
||||
this.parser.parser.yy = classDb;
|
||||
this.db = classDb;
|
||||
this.renderer = classRendererV2;
|
||||
break;
|
||||
case 'state':
|
||||
this.parser = stateParser;
|
||||
this.parser.parser.yy = stateDb;
|
||||
this.db = stateDb;
|
||||
this.renderer = stateRenderer;
|
||||
break;
|
||||
case 'stateDiagram':
|
||||
this.parser = stateParser;
|
||||
this.parser.parser.yy = stateDb;
|
||||
this.db = stateDb;
|
||||
this.renderer = stateRendererV2;
|
||||
break;
|
||||
case 'info':
|
||||
log.debug('info info info');
|
||||
this.parser = infoParser;
|
||||
this.parser.parser.yy = infoDb;
|
||||
this.db = infoDb;
|
||||
this.renderer = infoRenderer;
|
||||
break;
|
||||
case 'pie':
|
||||
log.debug('pie');
|
||||
this.parser = pieParser;
|
||||
this.parser.parser.yy = pieDb;
|
||||
this.db = pieDb;
|
||||
this.renderer = pieRenderer;
|
||||
break;
|
||||
case 'er':
|
||||
log.debug('er');
|
||||
this.parser = erParser;
|
||||
this.parser.parser.yy = erDb;
|
||||
this.db = erDb;
|
||||
this.renderer = erRenderer;
|
||||
break;
|
||||
case 'journey':
|
||||
log.debug('Journey');
|
||||
this.parser = journeyParser;
|
||||
this.parser.parser.yy = journeyDb;
|
||||
this.db = journeyDb;
|
||||
this.renderer = journeyRenderer;
|
||||
break;
|
||||
case 'requirement':
|
||||
case 'requirementDiagram':
|
||||
log.debug('RequirementDiagram');
|
||||
this.parser = requirementParser;
|
||||
this.parser.parser.yy = requirementDb;
|
||||
this.db = requirementDb;
|
||||
this.renderer = requirementRenderer;
|
||||
break;
|
||||
default:
|
||||
log.error('Unkown graphtype');
|
||||
throw new Error('Unkown graphtype');
|
||||
|
||||
// console.log('this.type', this.type, diagrams[this.type]);
|
||||
// Setup diagram
|
||||
this.db = diagrams[this.type].db;
|
||||
this.renderer = diagrams[this.type].renderer;
|
||||
this.parser = diagrams[this.type].parser;
|
||||
this.parser.parser.yy = this.db;
|
||||
if (typeof diagrams[this.type].init === 'function') {
|
||||
diagrams[this.type].init(cnf);
|
||||
log.debug('Initialized diagram ' + this.type, cnf);
|
||||
}
|
||||
this.txt = this.txt + '\n';
|
||||
|
||||
this.parser.parser.yy.graphType = this.type;
|
||||
this.parser.parser.yy.parseError = (str, hash) => {
|
||||
const error = { str, hash };
|
||||
throw error;
|
||||
};
|
||||
this.parser.parse(txt);
|
||||
this.parser.parse(this.txt);
|
||||
}
|
||||
parse(text) {
|
||||
var parseEncounteredException = false;
|
||||
try {
|
||||
text = text + '\n';
|
||||
this.db.clear();
|
||||
|
||||
this.parser.parse(text);
|
||||
} catch (error) {
|
||||
parseEncounteredException = true;
|
||||
// Is this the correct way to access mermiad's parseError()
|
||||
// method ? (or global.mermaid.parseError()) ?
|
||||
if (global.mermaid.parseError) {
|
||||
if (error.str != undefined) {
|
||||
// handle case where error string and hash were
|
||||
// wrapped in object like`const error = { str, hash };`
|
||||
global.mermaid.parseError(error.str, error.hash);
|
||||
} else {
|
||||
// assume it is just error string and pass it on
|
||||
global.mermaid.parseError(error);
|
||||
}
|
||||
} else {
|
||||
// No mermaid.parseError() handler defined, so re-throw it
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
return !parseEncounteredException;
|
||||
}
|
||||
getParser() {
|
||||
return this.parser;
|
||||
|
74
src/assignWithDepth.js
Normal file
74
src/assignWithDepth.js
Normal file
@ -0,0 +1,74 @@
|
||||
/**
|
||||
* @function assignWithDepth Extends the functionality of {@link ObjectConstructor.assign} with the
|
||||
* ability to merge arbitrary-depth objects For each key in src with path `k` (recursively)
|
||||
* performs an Object.assign(dst[`k`], src[`k`]) with a slight change from the typical handling of
|
||||
* undefined for dst[`k`]: instead of raising an error, dst[`k`] is auto-initialized to {} and
|
||||
* effectively merged with src[`k`]<p> Additionally, dissimilar types will not clobber unless the
|
||||
* config.clobber parameter === true. Example:
|
||||
*
|
||||
* ```js
|
||||
* let config_0 = { foo: { bar: 'bar' }, bar: 'foo' };
|
||||
* let config_1 = { foo: 'foo', bar: 'bar' };
|
||||
* let result = assignWithDepth(config_0, config_1);
|
||||
* console.log(result);
|
||||
* //-> result: { foo: { bar: 'bar' }, bar: 'bar' }
|
||||
* ```
|
||||
*
|
||||
* Traditional Object.assign would have clobbered foo in config_0 with foo in config_1. If src is a
|
||||
* destructured array of objects and dst is not an array, assignWithDepth will apply each element
|
||||
* of src to dst in order.
|
||||
* @param dst
|
||||
* @param src
|
||||
* @param config
|
||||
* @param dst
|
||||
* @param src
|
||||
* @param config
|
||||
* @param dst
|
||||
* @param src
|
||||
* @param config
|
||||
* @param {any} dst - The destination of the merge
|
||||
* @param {any} src - The source object(s) to merge into destination
|
||||
* @param {{ depth: number; clobber: boolean }} [config={ depth: 2, clobber: false }] - Depth: depth
|
||||
* to traverse within src and dst for merging - clobber: should dissimilar types clobber (default:
|
||||
* { depth: 2, clobber: false }). Default is `{ depth: 2, clobber: false }`
|
||||
* @returns {any}
|
||||
*/
|
||||
const assignWithDepth = function (dst, src, config) {
|
||||
const { depth, clobber } = Object.assign({ depth: 2, clobber: false }, config);
|
||||
if (Array.isArray(src) && !Array.isArray(dst)) {
|
||||
src.forEach((s) => assignWithDepth(dst, s, config));
|
||||
return dst;
|
||||
} else if (Array.isArray(src) && Array.isArray(dst)) {
|
||||
src.forEach((s) => {
|
||||
if (dst.indexOf(s) === -1) {
|
||||
dst.push(s);
|
||||
}
|
||||
});
|
||||
return dst;
|
||||
}
|
||||
if (typeof dst === 'undefined' || depth <= 0) {
|
||||
if (dst !== undefined && dst !== null && typeof dst === 'object' && typeof src === 'object') {
|
||||
return Object.assign(dst, src);
|
||||
} else {
|
||||
return src;
|
||||
}
|
||||
}
|
||||
if (typeof src !== 'undefined' && typeof dst === 'object' && typeof src === 'object') {
|
||||
Object.keys(src).forEach((key) => {
|
||||
if (
|
||||
typeof src[key] === 'object' &&
|
||||
(dst[key] === undefined || typeof dst[key] === 'object')
|
||||
) {
|
||||
if (dst[key] === undefined) {
|
||||
dst[key] = Array.isArray(src[key]) ? [] : {};
|
||||
}
|
||||
dst[key] = assignWithDepth(dst[key], src[key], { depth: depth - 1, clobber });
|
||||
} else if (clobber || (typeof dst[key] !== 'object' && typeof src[key] !== 'object')) {
|
||||
dst[key] = src[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
return dst;
|
||||
};
|
||||
|
||||
export default assignWithDepth;
|
@ -1,4 +1,4 @@
|
||||
import { assignWithDepth } from './utils';
|
||||
import assignWithDepth from './assignWithDepth';
|
||||
import { log } from './logger';
|
||||
import theme from './themes';
|
||||
import config from './defaultConfig';
|
||||
|
@ -2,6 +2,7 @@ import { select } from 'd3';
|
||||
import { log } from '../logger'; // eslint-disable-line
|
||||
import { getConfig } from '../config';
|
||||
import { sanitizeText, evaluate } from '../diagrams/common/common';
|
||||
import { decodeEntities } from '../mermaidAPI';
|
||||
|
||||
const sanitizeTxt = (txt) => sanitizeText(txt, getConfig());
|
||||
|
||||
@ -52,7 +53,7 @@ const createLabel = (_vertexText, style, isTitle, isNode) => {
|
||||
log.info('vertexText' + vertexText);
|
||||
const node = {
|
||||
isNode,
|
||||
label: vertexText.replace(
|
||||
label: decodeEntities(vertexText).replace(
|
||||
/fa[lrsb]?:fa-[\w-]+/g,
|
||||
(s) => `<i class='${s.replace(':', ' ')}'></i>`
|
||||
),
|
||||
|
@ -817,6 +817,9 @@ const config = {
|
||||
},
|
||||
class: {
|
||||
arrowMarkerAbsolute: false,
|
||||
dividerMargin: 10,
|
||||
padding: 5,
|
||||
textHeight: 10,
|
||||
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
|
100
src/diagram-api/detectType.js
Normal file
100
src/diagram-api/detectType.js
Normal file
@ -0,0 +1,100 @@
|
||||
const directive =
|
||||
/[%]{2}[{]\s*(?:(?:(\w+)\s*:|(\w+))\s*(?:(?:(\w+))|((?:(?![}][%]{2}).|\r?\n)*))?\s*)(?:[}][%]{2})?/gi;
|
||||
const anyComment = /\s*%%.*\n/gm;
|
||||
const detectors = {};
|
||||
/**
|
||||
* @function detectType Detects the type of the graph text. Takes into consideration the possible
|
||||
* existence of an %%init directive
|
||||
*
|
||||
* ```mermaid
|
||||
* %%{initialize: {"startOnLoad": true, logLevel: "fatal" }}%%
|
||||
* graph LR
|
||||
* a-->b
|
||||
* b-->c
|
||||
* c-->d
|
||||
* d-->e
|
||||
* e-->f
|
||||
* f-->g
|
||||
* g-->h
|
||||
* ```
|
||||
* @param {string} text The text defining the graph
|
||||
* @param {{
|
||||
* class: { defaultRenderer: string } | undefined;
|
||||
* state: { defaultRenderer: string } | undefined;
|
||||
* flowchart: { defaultRenderer: string } | undefined;
|
||||
* }} [cnf]
|
||||
* @returns {string} A graph definition key
|
||||
*/
|
||||
const detectType = function (text, cnf) {
|
||||
text = text.replace(directive, '').replace(anyComment, '\n');
|
||||
if (text.match(/^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/)) {
|
||||
return 'c4';
|
||||
}
|
||||
|
||||
if (text.match(/^\s*sequenceDiagram/)) {
|
||||
return 'sequence';
|
||||
}
|
||||
|
||||
if (text.match(/^\s*gantt/)) {
|
||||
return 'gantt';
|
||||
}
|
||||
if (text.match(/^\s*classDiagram-v2/)) {
|
||||
return 'classDiagram';
|
||||
}
|
||||
if (text.match(/^\s*classDiagram/)) {
|
||||
if (cnf && cnf.class && cnf.class.defaultRenderer === 'dagre-wrapper') return 'classDiagram';
|
||||
return 'class';
|
||||
}
|
||||
|
||||
if (text.match(/^\s*stateDiagram-v2/)) {
|
||||
return 'stateDiagram';
|
||||
}
|
||||
|
||||
if (text.match(/^\s*stateDiagram/)) {
|
||||
if (cnf && cnf.class && cnf.state.defaultRenderer === 'dagre-wrapper') return 'stateDiagram';
|
||||
return 'state';
|
||||
}
|
||||
|
||||
// if (text.match(/^\s*gitGraph/)) {
|
||||
// return 'gitGraph';
|
||||
// }
|
||||
if (text.match(/^\s*flowchart/)) {
|
||||
return 'flowchart-v2';
|
||||
}
|
||||
|
||||
if (text.match(/^\s*info/)) {
|
||||
return 'info';
|
||||
}
|
||||
if (text.match(/^\s*pie/)) {
|
||||
return 'pie';
|
||||
}
|
||||
|
||||
if (text.match(/^\s*erDiagram/)) {
|
||||
return 'er';
|
||||
}
|
||||
|
||||
if (text.match(/^\s*journey/)) {
|
||||
return 'journey';
|
||||
}
|
||||
|
||||
if (text.match(/^\s*requirement/) || text.match(/^\s*requirementDiagram/)) {
|
||||
return 'requirement';
|
||||
}
|
||||
if (cnf && cnf.flowchart && cnf.flowchart.defaultRenderer === 'dagre-wrapper')
|
||||
return 'flowchart-v2';
|
||||
const k = Object.keys(detectors);
|
||||
for (let i = 0; i < k.length; i++) {
|
||||
const key = k[i];
|
||||
const dia = detectors[key];
|
||||
if (dia && dia.detector(text)) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
return 'flowchart';
|
||||
};
|
||||
export const addDetector = (key, detector) => {
|
||||
detectors[key] = {
|
||||
detector,
|
||||
};
|
||||
};
|
||||
export default detectType;
|
32
src/diagram-api/diagram-orchestration.js
Normal file
32
src/diagram-api/diagram-orchestration.js
Normal file
@ -0,0 +1,32 @@
|
||||
import { registerDiagram } from './diagramAPI.js';
|
||||
// import mindmapDb from '../diagrams/mindmap/mindmapDb';
|
||||
// import mindmapRenderer from '../diagrams/mindmap/mindmapRenderer';
|
||||
// import mindmapParser from '../diagrams/mindmap/parser/mindmapDiagram';
|
||||
// import mindmapDetector from '../diagrams/mindmap/mindmapDetector';
|
||||
|
||||
import gitGraphDb from '../diagrams/git/gitGraphAst';
|
||||
import gitGraphRenderer from '../diagrams/git/gitGraphRenderer';
|
||||
import gitGraphParser from '../diagrams/git/parser/gitGraph';
|
||||
import gitGraphDetector from '../diagrams/git/gitGraphDetector';
|
||||
|
||||
// Register mindmap and other built-in diagrams
|
||||
// registerDiagram(
|
||||
// 'mindmap',
|
||||
// mindmapParser,
|
||||
// mindmapDb,
|
||||
// mindmapRenderer,
|
||||
// undefined,
|
||||
// mindmapRenderer,
|
||||
// mindmapDetector
|
||||
// );
|
||||
const addDiagrams = () => {
|
||||
registerDiagram(
|
||||
'gitGraph',
|
||||
gitGraphParser,
|
||||
gitGraphDb,
|
||||
gitGraphRenderer,
|
||||
undefined,
|
||||
gitGraphDetector
|
||||
);
|
||||
};
|
||||
export default addDiagrams;
|
175
src/diagram-api/diagramAPI.js
Normal file
175
src/diagram-api/diagramAPI.js
Normal file
@ -0,0 +1,175 @@
|
||||
import c4Db from '../diagrams/c4/c4Db';
|
||||
import c4Renderer from '../diagrams/c4/c4Renderer';
|
||||
import c4Parser from '../diagrams/c4/parser/c4Diagram';
|
||||
import classDb from '../diagrams/class/classDb';
|
||||
import classRenderer from '../diagrams/class/classRenderer';
|
||||
import classRendererV2 from '../diagrams/class/classRenderer-v2';
|
||||
import classParser from '../diagrams/class/parser/classDiagram';
|
||||
import erDb from '../diagrams/er/erDb';
|
||||
import erRenderer from '../diagrams/er/erRenderer';
|
||||
import erParser from '../diagrams/er/parser/erDiagram';
|
||||
import flowDb from '../diagrams/flowchart/flowDb';
|
||||
import flowRenderer from '../diagrams/flowchart/flowRenderer';
|
||||
import flowRendererV2 from '../diagrams/flowchart/flowRenderer-v2';
|
||||
import flowParser from '../diagrams/flowchart/parser/flow';
|
||||
import ganttDb from '../diagrams/gantt/ganttDb';
|
||||
import ganttRenderer from '../diagrams/gantt/ganttRenderer';
|
||||
import ganttParser from '../diagrams/gantt/parser/gantt';
|
||||
import infoDb from '../diagrams/info/infoDb';
|
||||
import infoRenderer from '../diagrams/info/infoRenderer';
|
||||
import infoParser from '../diagrams/info/parser/info';
|
||||
import pieParser from '../diagrams/pie/parser/pie';
|
||||
import pieDb from '../diagrams/pie/pieDb';
|
||||
import pieRenderer from '../diagrams/pie/pieRenderer';
|
||||
import requirementParser from '../diagrams/requirement/parser/requirementDiagram';
|
||||
import requirementDb from '../diagrams/requirement/requirementDb';
|
||||
import requirementRenderer from '../diagrams/requirement/requirementRenderer';
|
||||
import sequenceParser from '../diagrams/sequence/parser/sequenceDiagram';
|
||||
import sequenceDb from '../diagrams/sequence/sequenceDb';
|
||||
import sequenceRenderer from '../diagrams/sequence/sequenceRenderer';
|
||||
import stateParser from '../diagrams/state/parser/stateDiagram';
|
||||
import stateDb from '../diagrams/state/stateDb';
|
||||
import stateRenderer from '../diagrams/state/stateRenderer';
|
||||
import stateRendererV2 from '../diagrams/state/stateRenderer-v2';
|
||||
import journeyDb from '../diagrams/user-journey/journeyDb';
|
||||
import journeyRenderer from '../diagrams/user-journey/journeyRenderer';
|
||||
import journeyParser from '../diagrams/user-journey/parser/journey';
|
||||
import { addDetector } from './detectType';
|
||||
|
||||
const diagrams = {
|
||||
c4: {
|
||||
db: c4Db,
|
||||
renderer: c4Renderer,
|
||||
parser: c4Parser,
|
||||
init: (cnf) => {
|
||||
c4Renderer.setConf(cnf.c4);
|
||||
},
|
||||
},
|
||||
class: {
|
||||
db: classDb,
|
||||
renderer: classRenderer,
|
||||
parser: classParser,
|
||||
init: (cnf) => {
|
||||
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
classDb.clear();
|
||||
},
|
||||
},
|
||||
classDiagram: {
|
||||
db: classDb,
|
||||
renderer: classRendererV2,
|
||||
parser: classParser,
|
||||
init: (cnf) => {
|
||||
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
classDb.clear();
|
||||
},
|
||||
},
|
||||
er: {
|
||||
db: erDb,
|
||||
renderer: erRenderer,
|
||||
parser: erParser,
|
||||
},
|
||||
flowchart: {
|
||||
db: flowDb,
|
||||
renderer: flowRenderer,
|
||||
parser: flowParser,
|
||||
init: (cnf) => {
|
||||
flowRenderer.setConf(cnf.flowchart);
|
||||
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
flowDb.clear();
|
||||
flowDb.setGen('gen-1');
|
||||
},
|
||||
},
|
||||
'flowchart-v2': {
|
||||
db: flowDb,
|
||||
renderer: flowRendererV2,
|
||||
parser: flowParser,
|
||||
init: (cnf) => {
|
||||
flowRendererV2.setConf(cnf.flowchart);
|
||||
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
flowDb.clear();
|
||||
flowDb.setGen('gen-2');
|
||||
},
|
||||
},
|
||||
gantt: {
|
||||
db: ganttDb,
|
||||
renderer: ganttRenderer,
|
||||
parser: ganttParser,
|
||||
init: (cnf) => {
|
||||
ganttRenderer.setConf(cnf.gantt);
|
||||
},
|
||||
},
|
||||
// git: {
|
||||
// db: gitGraphAst,
|
||||
// renderer: gitGraphRenderer,
|
||||
// parser: gitGraphParser,
|
||||
// },
|
||||
info: {
|
||||
db: infoDb,
|
||||
renderer: infoRenderer,
|
||||
parser: infoParser,
|
||||
},
|
||||
pie: {
|
||||
db: pieDb,
|
||||
renderer: pieRenderer,
|
||||
parser: pieParser,
|
||||
},
|
||||
requirement: {
|
||||
db: requirementDb,
|
||||
renderer: requirementRenderer,
|
||||
parser: requirementParser,
|
||||
},
|
||||
sequence: {
|
||||
db: sequenceDb,
|
||||
renderer: sequenceRenderer,
|
||||
parser: sequenceParser,
|
||||
init: (cnf) => {
|
||||
cnf.sequence.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
if (cnf.sequenceDiagram) {
|
||||
// backwards compatibility
|
||||
sequenceRenderer.setConf(Object.assign(cnf.sequence, cnf.sequenceDiagram));
|
||||
console.error(
|
||||
'`mermaid config.sequenceDiagram` has been renamed to `config.sequence`. Please update your mermaid config.'
|
||||
);
|
||||
}
|
||||
sequenceDb.setWrap(cnf.wrap);
|
||||
sequenceRenderer.setConf(cnf.sequence);
|
||||
},
|
||||
},
|
||||
state: {
|
||||
db: stateDb,
|
||||
renderer: stateRenderer,
|
||||
parser: stateParser,
|
||||
init: (cnf) => {
|
||||
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
stateDb.clear();
|
||||
},
|
||||
},
|
||||
stateDiagram: {
|
||||
db: stateDb,
|
||||
renderer: stateRendererV2,
|
||||
parser: stateParser,
|
||||
init: (cnf) => {
|
||||
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
stateDb.clear();
|
||||
},
|
||||
},
|
||||
journey: {
|
||||
db: journeyDb,
|
||||
renderer: journeyRenderer,
|
||||
parser: journeyParser,
|
||||
init: (cnf) => {
|
||||
journeyRenderer.setConf(cnf.journey);
|
||||
journeyDb.clear();
|
||||
},
|
||||
},
|
||||
};
|
||||
// console.log(sequenceDb);
|
||||
export const registerDiagram = (id, parser, db, renderer, init, detector) => {
|
||||
diagrams[id] = { parser, db, renderer, init };
|
||||
addDetector(id, detector);
|
||||
};
|
||||
|
||||
export const getDiagrams = () => {
|
||||
// console.log('diagrams', diagrams);
|
||||
return diagrams;
|
||||
};
|
@ -5,13 +5,8 @@ import { parser } from './parser/c4Diagram';
|
||||
import common from '../common/common';
|
||||
import c4Db from './c4Db';
|
||||
import * as configApi from '../../config';
|
||||
import utils, {
|
||||
wrapLabel,
|
||||
calculateTextWidth,
|
||||
calculateTextHeight,
|
||||
assignWithDepth,
|
||||
configureSvgSize,
|
||||
} from '../../utils';
|
||||
import assignWithDepth from '../../assignWithDepth';
|
||||
import { wrapLabel, calculateTextWidth, calculateTextHeight, configureSvgSize } from '../../utils';
|
||||
import addSVGAccessibilityFields from '../../accessibility';
|
||||
|
||||
let globalBoundaryMaxX = 0,
|
||||
@ -25,7 +20,7 @@ parser.yy = c4Db;
|
||||
let conf = {};
|
||||
|
||||
class Bounds {
|
||||
constructor() {
|
||||
constructor(diagObj) {
|
||||
this.name = '';
|
||||
this.data = {};
|
||||
this.data.startx = undefined;
|
||||
@ -41,7 +36,7 @@ class Bounds {
|
||||
this.nextData.stopy = undefined;
|
||||
this.nextData.cnt = 0;
|
||||
|
||||
setConf(parser.yy.getConfig());
|
||||
setConf(diagObj.db.getConfig());
|
||||
}
|
||||
|
||||
setData(startx, stopx, starty, stopy) {
|
||||
@ -96,7 +91,7 @@ class Bounds {
|
||||
this.updateVal(this.nextData, 'stopy', _stopy, Math.max);
|
||||
}
|
||||
|
||||
init() {
|
||||
init(diagObj) {
|
||||
this.name = '';
|
||||
this.data = {
|
||||
startx: undefined,
|
||||
@ -112,7 +107,7 @@ class Bounds {
|
||||
stopy: undefined,
|
||||
cnt: 0,
|
||||
};
|
||||
setConf(parser.yy.getConfig());
|
||||
setConf(diagObj.db.getConfig());
|
||||
}
|
||||
|
||||
bumpLastMargin(margin) {
|
||||
@ -411,13 +406,13 @@ let getIntersectPoints = function (fromNode, endNode) {
|
||||
return { startPoint: startPoint, endPoint: endPoint };
|
||||
};
|
||||
|
||||
export const drawRels = function (diagram, rels, getC4ShapeObj) {
|
||||
export const drawRels = function (diagram, rels, getC4ShapeObj, diagObj) {
|
||||
let i = 0;
|
||||
for (let rel of rels) {
|
||||
i = i + 1;
|
||||
let relTextWrap = rel.wrap && conf.wrap;
|
||||
let relConf = messageFont(conf);
|
||||
let diagramType = parser.yy.getC4Type();
|
||||
let diagramType = diagObj.db.getC4Type();
|
||||
if (diagramType === 'C4Dynamic') rel.label.text = i + ': ' + rel.label.text;
|
||||
let textLimitWidth = calculateTextWidth(rel.label.text, relConf);
|
||||
calcC4ShapeTextWH('label', rel, relTextWrap, relConf, textLimitWidth);
|
||||
@ -446,9 +441,10 @@ export const drawRels = function (diagram, rels, getC4ShapeObj) {
|
||||
* @param parentBoundaryAlias
|
||||
* @param parentBounds
|
||||
* @param currentBoundarys
|
||||
* @param diagObj
|
||||
*/
|
||||
function drawInsideBoundary(diagram, parentBoundaryAlias, parentBounds, currentBoundarys) {
|
||||
let currentBounds = new Bounds();
|
||||
function drawInsideBoundary(diagram, parentBoundaryAlias, parentBounds, currentBoundarys, diagObj) {
|
||||
let currentBounds = new Bounds(diagObj);
|
||||
// Calculate the width limit of the boundar. label/type 的长度,
|
||||
currentBounds.data.widthLimit =
|
||||
parentBounds.data.widthLimit / Math.min(c4BoundaryInRow, currentBoundarys.length);
|
||||
@ -527,8 +523,8 @@ function drawInsideBoundary(diagram, parentBoundaryAlias, parentBounds, currentB
|
||||
currentBounds.setData(_x, _x, _y, _y);
|
||||
}
|
||||
currentBounds.name = currentBoundary.alias;
|
||||
let currentPersonOrSystemArray = parser.yy.getC4ShapeArray(currentBoundary.alias);
|
||||
let currentPersonOrSystemKeys = parser.yy.getC4ShapeKeys(currentBoundary.alias);
|
||||
let currentPersonOrSystemArray = diagObj.db.getC4ShapeArray(currentBoundary.alias);
|
||||
let currentPersonOrSystemKeys = diagObj.db.getC4ShapeKeys(currentBoundary.alias);
|
||||
|
||||
if (currentPersonOrSystemKeys.length > 0) {
|
||||
drawC4ShapeArray(
|
||||
@ -539,13 +535,19 @@ function drawInsideBoundary(diagram, parentBoundaryAlias, parentBounds, currentB
|
||||
);
|
||||
}
|
||||
parentBoundaryAlias = currentBoundary.alias;
|
||||
let nextCurrentBoundarys = parser.yy.getBoundarys(parentBoundaryAlias);
|
||||
let nextCurrentBoundarys = diagObj.db.getBoundarys(parentBoundaryAlias);
|
||||
|
||||
if (nextCurrentBoundarys.length > 0) {
|
||||
// draw boundary inside currentBoundary
|
||||
// bounds.init();
|
||||
// parentBoundaryWidthLimit = bounds.data.stopx - bounds.startx;
|
||||
drawInsideBoundary(diagram, parentBoundaryAlias, currentBounds, nextCurrentBoundarys);
|
||||
drawInsideBoundary(
|
||||
diagram,
|
||||
parentBoundaryAlias,
|
||||
currentBounds,
|
||||
nextCurrentBoundarys,
|
||||
diagObj
|
||||
);
|
||||
}
|
||||
// draw boundary
|
||||
if (currentBoundary.alias !== 'global') drawBoundary(diagram, currentBoundary, currentBounds);
|
||||
@ -566,9 +568,12 @@ function drawInsideBoundary(diagram, parentBoundaryAlias, parentBounds, currentB
|
||||
* Draws a sequenceDiagram in the tag with id: id based on the graph definition in text.
|
||||
*
|
||||
* @param {any} text
|
||||
* @param _text
|
||||
* @param {any} id
|
||||
* @param _version
|
||||
* @param diagObj
|
||||
*/
|
||||
export const draw = function (text, id) {
|
||||
export const draw = function (_text, id, _version, diagObj) {
|
||||
conf = configApi.getConfig().c4;
|
||||
const securityLevel = configApi.getConfig().securityLevel;
|
||||
// Handle root and Document for when rendering in sanbox mode
|
||||
@ -580,13 +585,10 @@ export const draw = function (text, id) {
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
let db = parser.yy;
|
||||
let db = diagObj.db;
|
||||
|
||||
parser.yy.clear();
|
||||
parser.yy.setWrap(conf.wrap);
|
||||
parser.parse(text + '\n');
|
||||
diagObj.db.setWrap(conf.wrap);
|
||||
|
||||
c4ShapeInRow = db.getC4ShapeInRow();
|
||||
c4BoundaryInRow = db.getC4BoundaryInRow();
|
||||
@ -600,7 +602,7 @@ export const draw = function (text, id) {
|
||||
svgDraw.insertDatabaseIcon(diagram);
|
||||
svgDraw.insertClockIcon(diagram);
|
||||
|
||||
let screenBounds = new Bounds();
|
||||
let screenBounds = new Bounds(diagObj);
|
||||
|
||||
screenBounds.setData(
|
||||
conf.diagramMarginX,
|
||||
@ -613,12 +615,12 @@ export const draw = function (text, id) {
|
||||
globalBoundaryMaxX = conf.diagramMarginX;
|
||||
globalBoundaryMaxY = conf.diagramMarginY;
|
||||
|
||||
const title = parser.yy.getTitle();
|
||||
const c4type = parser.yy.getC4Type();
|
||||
let currentBoundarys = parser.yy.getBoundarys('');
|
||||
const title = diagObj.db.getTitle();
|
||||
const c4type = diagObj.db.getC4Type();
|
||||
let currentBoundarys = diagObj.db.getBoundarys('');
|
||||
// switch (c4type) {
|
||||
// case 'C4Context':
|
||||
drawInsideBoundary(diagram, '', screenBounds, currentBoundarys);
|
||||
drawInsideBoundary(diagram, '', screenBounds, currentBoundarys, diagObj);
|
||||
// break;
|
||||
// }
|
||||
|
||||
@ -628,7 +630,7 @@ export const draw = function (text, id) {
|
||||
svgDraw.insertArrowCrossHead(diagram);
|
||||
svgDraw.insertArrowFilledHead(diagram);
|
||||
|
||||
drawRels(diagram, parser.yy.getRels(), parser.yy.getC4Shape);
|
||||
drawRels(diagram, diagObj.db.getRels(), diagObj.db.getC4Shape, diagObj);
|
||||
|
||||
screenBounds.data.stopx = globalBoundaryMaxX;
|
||||
screenBounds.data.stopy = globalBoundaryMaxY;
|
||||
|
@ -1,10 +1,6 @@
|
||||
import { select } from 'd3';
|
||||
import dagre from 'dagre';
|
||||
import graphlib from 'graphlib';
|
||||
import { log } from '../../logger';
|
||||
import classDb, { lookUpDomId } from './classDb';
|
||||
import { parser } from './parser/classDiagram';
|
||||
import svgDraw from './svgDraw';
|
||||
import { getConfig } from '../../config';
|
||||
import { render } from '../../dagre-wrapper/index.js';
|
||||
// import addHtmlLabel from 'dagre-d3/lib/label/add-html-label.js';
|
||||
@ -13,14 +9,12 @@ import { interpolateToCurve, getStylesFromArray, setupGraphViewbox } from '../..
|
||||
import common from '../common/common';
|
||||
import addSVGAccessibilityFields from '../../accessibility';
|
||||
|
||||
parser.yy = classDb;
|
||||
|
||||
let idCache = {};
|
||||
const padding = 20;
|
||||
|
||||
const sanitizeText = (txt) => common.sanitizeText(txt, getConfig());
|
||||
|
||||
const conf = {
|
||||
let conf = {
|
||||
dividerMargin: 10,
|
||||
padding: 5,
|
||||
textHeight: 10,
|
||||
@ -144,6 +138,7 @@ export const addClasses = function (classes, g) {
|
||||
* @param {object} g The graph object
|
||||
*/
|
||||
export const addRelations = function (relations, g) {
|
||||
const conf = getConfig().flowchart;
|
||||
let cnt = 0;
|
||||
|
||||
let defaultStyle;
|
||||
@ -269,16 +264,18 @@ export const setConf = function (cnf) {
|
||||
*
|
||||
* @param {string} text
|
||||
* @param {string} id
|
||||
* @param _version
|
||||
* @param diagObj
|
||||
*/
|
||||
export const draw = function (text, id) {
|
||||
export const draw = function (text, id, _version, diagObj) {
|
||||
log.info('Drawing class - ', id);
|
||||
classDb.clear();
|
||||
// const parser = classDb.parser;
|
||||
// diagObj.db.clear();
|
||||
// const parser = diagObj.db.parser;
|
||||
// parser.yy = classDb;
|
||||
|
||||
// Parse the graph definition
|
||||
// try {
|
||||
parser.parse(text);
|
||||
// parser.parse(text);
|
||||
// } catch (err) {
|
||||
// log.debug('Parsing failed');
|
||||
// }
|
||||
@ -298,7 +295,7 @@ export const draw = function (text, id) {
|
||||
compound: true,
|
||||
})
|
||||
.setGraph({
|
||||
rankdir: classDb.getDirection(),
|
||||
rankdir: diagObj.db.getDirection(),
|
||||
nodesep: nodeSpacing,
|
||||
ranksep: rankSpacing,
|
||||
marginx: 8,
|
||||
@ -318,8 +315,8 @@ export const draw = function (text, id) {
|
||||
// }
|
||||
|
||||
// Fetch the vertices/nodes and edges/links from the parsed graph definition
|
||||
const classes = classDb.getClasses();
|
||||
const relations = classDb.getRelations();
|
||||
const classes = diagObj.db.getClasses();
|
||||
const relations = diagObj.db.getRelations();
|
||||
|
||||
log.info(relations);
|
||||
addClasses(classes, g, id);
|
||||
@ -338,7 +335,6 @@ export const draw = function (text, id) {
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const svg = root.select(`[id="${id}"]`);
|
||||
svg.attr('xmlns:xlink', 'http://www.w3.org/1999/xlink');
|
||||
|
||||
// Run the renderer. This is what draws the final graph.
|
||||
const element = root.select('#' + id + ' g');
|
||||
@ -367,7 +363,7 @@ export const draw = function (text, id) {
|
||||
}
|
||||
}
|
||||
|
||||
addSVGAccessibilityFields(parser.yy, svg, id);
|
||||
addSVGAccessibilityFields(diagObj.db, svg, id);
|
||||
// If node has a link, wrap it in an anchor SVG object.
|
||||
// const keys = Object.keys(classes);
|
||||
// keys.forEach(function(key) {
|
||||
|
@ -2,19 +2,15 @@ import { select } from 'd3';
|
||||
import dagre from 'dagre';
|
||||
import graphlib from 'graphlib';
|
||||
import { log } from '../../logger';
|
||||
import classDb, { lookUpDomId } from './classDb';
|
||||
import { parser } from './parser/classDiagram';
|
||||
import svgDraw from './svgDraw';
|
||||
import { configureSvgSize } from '../../utils';
|
||||
import { getConfig } from '../../config';
|
||||
import addSVGAccessibilityFields from '../../accessibility';
|
||||
|
||||
parser.yy = classDb;
|
||||
|
||||
let idCache = {};
|
||||
const padding = 20;
|
||||
|
||||
const conf = {
|
||||
const confa = {
|
||||
dividerMargin: 10,
|
||||
padding: 5,
|
||||
textHeight: 10,
|
||||
@ -141,29 +137,20 @@ const insertMarkers = function (elem) {
|
||||
.attr('d', 'M 18,7 L9,13 L14,7 L9,1 Z');
|
||||
};
|
||||
|
||||
/**
|
||||
* Merges the value of `conf` with the passed `cnf`
|
||||
*
|
||||
* @param {object} cnf Config to merge
|
||||
*/
|
||||
export const setConf = function (cnf) {
|
||||
const keys = Object.keys(cnf);
|
||||
|
||||
keys.forEach(function (key) {
|
||||
conf[key] = cnf[key];
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Draws a flowchart in the tag with id: id based on the graph definition in text.
|
||||
*
|
||||
* @param {string} text
|
||||
* @param {string} id
|
||||
* @param version
|
||||
* @param _version
|
||||
* @param diagObj
|
||||
*/
|
||||
export const draw = function (text, id) {
|
||||
export const draw = function (text, id, _version, diagObj) {
|
||||
const conf = getConfig().class;
|
||||
idCache = {};
|
||||
parser.yy.clear();
|
||||
parser.parse(text);
|
||||
// diagObj.db.clear();
|
||||
// diagObj.parser.parse(text);
|
||||
|
||||
log.info('Rendering diagram ' + text);
|
||||
|
||||
@ -181,7 +168,6 @@ export const draw = function (text, id) {
|
||||
|
||||
// Fetch the default direction, use TD if none was found
|
||||
const diagram = root.select(`[id='${id}']`);
|
||||
diagram.attr('xmlns:xlink', 'http://www.w3.org/1999/xlink');
|
||||
insertMarkers(diagram);
|
||||
|
||||
// Layout graph, Create a new directed graph
|
||||
@ -199,12 +185,12 @@ export const draw = function (text, id) {
|
||||
return {};
|
||||
});
|
||||
|
||||
const classes = classDb.getClasses();
|
||||
const classes = diagObj.db.getClasses();
|
||||
const keys = Object.keys(classes);
|
||||
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const classDef = classes[keys[i]];
|
||||
const node = svgDraw.drawClass(diagram, classDef, conf);
|
||||
const node = svgDraw.drawClass(diagram, classDef, conf, diagObj);
|
||||
idCache[node.id] = node;
|
||||
|
||||
// Add nodes to the graph. The first argument is the node id. The second is
|
||||
@ -215,7 +201,7 @@ export const draw = function (text, id) {
|
||||
log.info('Org height: ' + node.height);
|
||||
}
|
||||
|
||||
const relations = classDb.getRelations();
|
||||
const relations = diagObj.db.getRelations();
|
||||
relations.forEach(function (relation) {
|
||||
log.info(
|
||||
'tjoho' + getGraphId(relation.id1) + getGraphId(relation.id2) + JSON.stringify(relation)
|
||||
@ -235,7 +221,7 @@ export const draw = function (text, id) {
|
||||
if (typeof v !== 'undefined' && typeof g.node(v) !== 'undefined') {
|
||||
log.debug('Node ' + v + ': ' + JSON.stringify(g.node(v)));
|
||||
root
|
||||
.select('#' + lookUpDomId(v))
|
||||
.select('#' + diagObj.db.lookUpDomId(v))
|
||||
.attr(
|
||||
'transform',
|
||||
'translate(' +
|
||||
@ -250,7 +236,7 @@ export const draw = function (text, id) {
|
||||
g.edges().forEach(function (e) {
|
||||
if (typeof e !== 'undefined' && typeof g.edge(e) !== 'undefined') {
|
||||
log.debug('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(g.edge(e)));
|
||||
svgDraw.drawEdge(diagram, g.edge(e), g.edge(e).relation, conf);
|
||||
svgDraw.drawEdge(diagram, g.edge(e), g.edge(e).relation, conf, diagObj);
|
||||
}
|
||||
});
|
||||
|
||||
@ -264,10 +250,9 @@ export const draw = function (text, id) {
|
||||
const vBox = `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`;
|
||||
log.debug(`viewBox ${vBox}`);
|
||||
diagram.attr('viewBox', vBox);
|
||||
addSVGAccessibilityFields(parser.yy, diagram, id);
|
||||
addSVGAccessibilityFields(diagObj.db, diagram, id);
|
||||
};
|
||||
|
||||
export default {
|
||||
setConf,
|
||||
draw,
|
||||
};
|
||||
|
@ -1,19 +1,18 @@
|
||||
import { line, curveBasis } from 'd3';
|
||||
import { lookUpDomId, relationType } from './classDb';
|
||||
import utils from '../../utils';
|
||||
import { log } from '../../logger';
|
||||
|
||||
let edgeCount = 0;
|
||||
export const drawEdge = function (elem, path, relation, conf) {
|
||||
export const drawEdge = function (elem, path, relation, conf, diagObj) {
|
||||
const getRelationType = function (type) {
|
||||
switch (type) {
|
||||
case relationType.AGGREGATION:
|
||||
case diagObj.db.relationType.AGGREGATION:
|
||||
return 'aggregation';
|
||||
case relationType.EXTENSION:
|
||||
case diagObj.db.EXTENSION:
|
||||
return 'extension';
|
||||
case relationType.COMPOSITION:
|
||||
case diagObj.db.COMPOSITION:
|
||||
return 'composition';
|
||||
case relationType.DEPENDENCY:
|
||||
case diagObj.db.DEPENDENCY:
|
||||
return 'dependency';
|
||||
}
|
||||
};
|
||||
@ -150,10 +149,11 @@ export const drawEdge = function (elem, path, relation, conf) {
|
||||
* @param {SVGSVGElement} elem The element to draw it into
|
||||
* @param classDef
|
||||
* @param conf
|
||||
* @param diagObj
|
||||
* @todo Add more information in the JSDOC here
|
||||
*/
|
||||
export const drawClass = function (elem, classDef, conf) {
|
||||
log.info('Rendering class ' + classDef);
|
||||
export const drawClass = function (elem, classDef, conf, diagObj) {
|
||||
log.debug('Rendering class ', classDef, conf);
|
||||
|
||||
const id = classDef.id;
|
||||
const classInfo = {
|
||||
@ -164,7 +164,7 @@ export const drawClass = function (elem, classDef, conf) {
|
||||
};
|
||||
|
||||
// add class group
|
||||
const g = elem.append('g').attr('id', lookUpDomId(id)).attr('class', 'classGroup');
|
||||
const g = elem.append('g').attr('id', diagObj.db.lookUpDomId(id)).attr('class', 'classGroup');
|
||||
|
||||
// add title
|
||||
let title;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import graphlib from 'graphlib';
|
||||
import { line, curveBasis, select } from 'd3';
|
||||
import erDb from './erDb';
|
||||
import erParser from './parser/erDiagram';
|
||||
// import erDb from './erDb';
|
||||
// import erParser from './parser/erDiagram';
|
||||
import dagre from 'dagre';
|
||||
import { getConfig } from '../../config';
|
||||
import { log } from '../../logger';
|
||||
@ -9,7 +9,7 @@ import erMarkers from './erMarkers';
|
||||
import { configureSvgSize } from '../../utils';
|
||||
import addSVGAccessibilityFields from '../../accessibility';
|
||||
|
||||
const conf = {};
|
||||
let conf = {};
|
||||
|
||||
/**
|
||||
* Allows the top-level API module to inject config specific to this renderer, storing it in the
|
||||
@ -409,8 +409,9 @@ let relCnt = 0;
|
||||
* @param g The graph containing the edge information
|
||||
* @param insert The insertion point in the svg DOM (because relationships have markers that need to
|
||||
* sit 'behind' opaque entity boxes)
|
||||
* @param diagObj
|
||||
*/
|
||||
const drawRelationshipFromLayout = function (svg, rel, g, insert) {
|
||||
const drawRelationshipFromLayout = function (svg, rel, g, insert, diagObj) {
|
||||
relCnt++;
|
||||
|
||||
// Find the edge relating to this relationship
|
||||
@ -435,7 +436,7 @@ const drawRelationshipFromLayout = function (svg, rel, g, insert) {
|
||||
.attr('fill', 'none');
|
||||
|
||||
// ...and with dashes if necessary
|
||||
if (rel.relSpec.relType === erDb.Identification.NON_IDENTIFYING) {
|
||||
if (rel.relSpec.relType === diagObj.db.Identification.NON_IDENTIFYING) {
|
||||
svgPath.attr('stroke-dasharray', '8,8');
|
||||
}
|
||||
|
||||
@ -457,40 +458,40 @@ const drawRelationshipFromLayout = function (svg, rel, g, insert) {
|
||||
|
||||
// Note that the 'A' entity's marker is at the end of the relationship and the 'B' entity's marker is at the start
|
||||
switch (rel.relSpec.cardA) {
|
||||
case erDb.Cardinality.ZERO_OR_ONE:
|
||||
case diagObj.db.Cardinality.ZERO_OR_ONE:
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_ONE_END + ')');
|
||||
break;
|
||||
case erDb.Cardinality.ZERO_OR_MORE:
|
||||
case diagObj.db.Cardinality.ZERO_OR_MORE:
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_MORE_END + ')');
|
||||
break;
|
||||
case erDb.Cardinality.ONE_OR_MORE:
|
||||
case diagObj.db.Cardinality.ONE_OR_MORE:
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ONE_OR_MORE_END + ')');
|
||||
break;
|
||||
case erDb.Cardinality.ONLY_ONE:
|
||||
case diagObj.db.Cardinality.ONLY_ONE:
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_END + ')');
|
||||
break;
|
||||
}
|
||||
|
||||
switch (rel.relSpec.cardB) {
|
||||
case erDb.Cardinality.ZERO_OR_ONE:
|
||||
case diagObj.db.Cardinality.ZERO_OR_ONE:
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_ONE_START + ')'
|
||||
);
|
||||
break;
|
||||
case erDb.Cardinality.ZERO_OR_MORE:
|
||||
case diagObj.db.Cardinality.ZERO_OR_MORE:
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_MORE_START + ')'
|
||||
);
|
||||
break;
|
||||
case erDb.Cardinality.ONE_OR_MORE:
|
||||
case diagObj.db.Cardinality.ONE_OR_MORE:
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + erMarkers.ERMarkers.ONE_OR_MORE_START + ')'
|
||||
);
|
||||
break;
|
||||
case erDb.Cardinality.ONLY_ONE:
|
||||
case diagObj.db.Cardinality.ONLY_ONE:
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_START + ')');
|
||||
break;
|
||||
}
|
||||
@ -540,12 +541,14 @@ const drawRelationshipFromLayout = function (svg, rel, g, insert) {
|
||||
*
|
||||
* @param text The text of the diagram
|
||||
* @param id The unique id of the DOM node that contains the diagram
|
||||
* @param _version
|
||||
* @param diag
|
||||
* @param diagObj
|
||||
*/
|
||||
export const draw = function (text, id) {
|
||||
export const draw = function (text, id, _version, diagObj) {
|
||||
conf = getConfig().er;
|
||||
log.info('Drawing ER diagram');
|
||||
erDb.clear();
|
||||
const parser = erParser.parser;
|
||||
parser.yy = erDb;
|
||||
// diag.db.clear();
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
// Handle root and Document for when rendering in sanbox mode
|
||||
let sandboxElement;
|
||||
@ -556,14 +559,14 @@ export const draw = function (text, id) {
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
// const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
// Parse the text to populate erDb
|
||||
try {
|
||||
parser.parse(text);
|
||||
} catch (err) {
|
||||
log.debug('Parsing failed');
|
||||
}
|
||||
// try {
|
||||
// parser.parse(text);
|
||||
// } catch (err) {
|
||||
// log.debug('Parsing failed');
|
||||
// }
|
||||
|
||||
// Get a reference to the svg node that contains the text
|
||||
const svg = root.select(`[id='${id}']`);
|
||||
@ -612,12 +615,12 @@ export const draw = function (text, id) {
|
||||
|
||||
// Draw the entities (at 0,0), returning the first svg node that got
|
||||
// inserted - this represents the insertion point for relationship paths
|
||||
const firstEntity = drawEntities(svg, erDb.getEntities(), g);
|
||||
const firstEntity = drawEntities(svg, diagObj.db.getEntities(), g);
|
||||
|
||||
// TODO: externalise the addition of entities to the graph - it's a bit 'buried' in the above
|
||||
|
||||
// Add all the relationships to the graph
|
||||
const relationships = addRelationships(erDb.getRelationships(), g);
|
||||
const relationships = addRelationships(diagObj.db.getRelationships(), g);
|
||||
|
||||
dagre.layout(g); // Node and edge positions will be updated
|
||||
|
||||
@ -626,7 +629,7 @@ export const draw = function (text, id) {
|
||||
|
||||
// Draw the relationships
|
||||
relationships.forEach(function (rel) {
|
||||
drawRelationshipFromLayout(svg, rel, g, firstEntity);
|
||||
drawRelationshipFromLayout(svg, rel, g, firstEntity, diagObj);
|
||||
});
|
||||
|
||||
const padding = conf.diagramPadding;
|
||||
@ -639,7 +642,7 @@ export const draw = function (text, id) {
|
||||
|
||||
svg.attr('viewBox', `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`);
|
||||
|
||||
addSVGAccessibilityFields(parser.yy, svg, id);
|
||||
addSVGAccessibilityFields(diagObj.db, svg, id);
|
||||
}; // draw
|
||||
|
||||
export default {
|
||||
|
@ -489,7 +489,6 @@ export const addSubGraph = function (_id, list, _title) {
|
||||
const { nodeList: nl, dir } = uniq(nodeList.concat.apply(nodeList, list));
|
||||
nodeList = nl;
|
||||
if (version === 'gen-1') {
|
||||
log.warn('LOOKING UP');
|
||||
for (let i = 0; i < nodeList.length; i++) {
|
||||
nodeList[i] = lookUpDomId(nodeList[i]);
|
||||
}
|
||||
|
@ -28,8 +28,9 @@ export const setConf = function (cnf) {
|
||||
* @param svgId
|
||||
* @param root
|
||||
* @param doc
|
||||
* @param diagObj
|
||||
*/
|
||||
export const addVertices = function (vert, g, svgId, root, doc) {
|
||||
export const addVertices = function (vert, g, svgId, root, doc, diagObj) {
|
||||
const svg = root.select(`[id="${svgId}"]`);
|
||||
const keys = Object.keys(vert);
|
||||
|
||||
@ -152,8 +153,8 @@ export const addVertices = function (vert, g, svgId, root, doc) {
|
||||
id: vertex.id,
|
||||
link: vertex.link,
|
||||
linkTarget: vertex.linkTarget,
|
||||
tooltip: flowDb.getTooltip(vertex.id) || '',
|
||||
domId: flowDb.lookUpDomId(vertex.id),
|
||||
tooltip: diagObj.db.getTooltip(vertex.id) || '',
|
||||
domId: diagObj.db.lookUpDomId(vertex.id),
|
||||
haveCallback: vertex.haveCallback,
|
||||
width: vertex.type === 'group' ? 500 : undefined,
|
||||
dir: vertex.dir,
|
||||
@ -171,7 +172,7 @@ export const addVertices = function (vert, g, svgId, root, doc) {
|
||||
class: classStr,
|
||||
style: styles.style,
|
||||
id: vertex.id,
|
||||
domId: flowDb.lookUpDomId(vertex.id),
|
||||
domId: diagObj.db.lookUpDomId(vertex.id),
|
||||
width: vertex.type === 'group' ? 500 : undefined,
|
||||
type: vertex.type,
|
||||
dir: vertex.dir,
|
||||
@ -186,8 +187,9 @@ export const addVertices = function (vert, g, svgId, root, doc) {
|
||||
*
|
||||
* @param {object} edges The edges to add to the graph
|
||||
* @param {object} g The graph object
|
||||
* @param diagObj
|
||||
*/
|
||||
export const addEdges = function (edges, g) {
|
||||
export const addEdges = function (edges, g, diagObj) {
|
||||
log.info('abc78 edges = ', edges);
|
||||
let cnt = 0;
|
||||
let linkIdCnt = {};
|
||||
@ -304,11 +306,7 @@ export const addEdges = function (edges, g) {
|
||||
edgeData.arrowheadStyle = 'fill: #333';
|
||||
edgeData.labelpos = 'c';
|
||||
}
|
||||
// if (evaluate(getConfig().flowchart.htmlLabels) && false) {
|
||||
// // eslint-disable-line
|
||||
// edgeData.labelType = 'html';
|
||||
// edgeData.label = `<span id="L-${linkId}" class="edgeLabel L-${linkNameStart}' L-${linkNameEnd}">${edge.text}</span>`;
|
||||
// } else {
|
||||
|
||||
edgeData.labelType = 'text';
|
||||
edgeData.label = edge.text.replace(common.lineBreakRegex, '\n');
|
||||
|
||||
@ -317,7 +315,6 @@ export const addEdges = function (edges, g) {
|
||||
}
|
||||
|
||||
edgeData.labelStyle = edgeData.labelStyle.replace('color:', 'fill:');
|
||||
// }
|
||||
|
||||
edgeData.id = linkId;
|
||||
edgeData.classes = 'flowchart-link ' + linkNameStart + ' ' + linkNameEnd;
|
||||
@ -331,22 +328,19 @@ export const addEdges = function (edges, g) {
|
||||
* Returns the all the styles from classDef statements in the graph definition.
|
||||
*
|
||||
* @param text
|
||||
* @param diagObj
|
||||
* @returns {object} ClassDef styles
|
||||
*/
|
||||
export const getClasses = function (text) {
|
||||
export const getClasses = function (text, diagObj) {
|
||||
log.info('Extracting classes');
|
||||
flowDb.clear();
|
||||
const parser = flow.parser;
|
||||
parser.yy = flowDb;
|
||||
|
||||
diagObj.db.clear();
|
||||
try {
|
||||
// Parse the graph definition
|
||||
parser.parse(text);
|
||||
diagObj.parse(text);
|
||||
return diagObj.db.getClasses();
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
return flowDb.getClasses();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -356,22 +350,15 @@ export const getClasses = function (text) {
|
||||
* @param id
|
||||
*/
|
||||
|
||||
export const draw = function (text, id) {
|
||||
export const draw = function (text, id, _version, diagObj) {
|
||||
log.info('Drawing flowchart');
|
||||
flowDb.clear();
|
||||
diagObj.db.clear();
|
||||
flowDb.setGen('gen-2');
|
||||
const parser = flow.parser;
|
||||
parser.yy = flowDb;
|
||||
|
||||
// Parse the graph definition
|
||||
// try {
|
||||
parser.parse(text);
|
||||
// } catch (err) {
|
||||
// log.debug('Parsing failed');
|
||||
// }
|
||||
diagObj.parser.parse(text);
|
||||
|
||||
// Fetch the default direction, use TD if none was found
|
||||
let dir = flowDb.getDirection();
|
||||
let dir = diagObj.db.getDirection();
|
||||
if (typeof dir === 'undefined') {
|
||||
dir = 'TD';
|
||||
}
|
||||
@ -409,18 +396,18 @@ export const draw = function (text, id) {
|
||||
});
|
||||
|
||||
let subG;
|
||||
const subGraphs = flowDb.getSubGraphs();
|
||||
const subGraphs = diagObj.db.getSubGraphs();
|
||||
log.info('Subgraphs - ', subGraphs);
|
||||
for (let i = subGraphs.length - 1; i >= 0; i--) {
|
||||
subG = subGraphs[i];
|
||||
log.info('Subgraph - ', subG);
|
||||
flowDb.addVertex(subG.id, subG.title, 'group', undefined, subG.classes, subG.dir);
|
||||
diagObj.db.addVertex(subG.id, subG.title, 'group', undefined, subG.classes, subG.dir);
|
||||
}
|
||||
|
||||
// Fetch the vertices/nodes and edges/links from the parsed graph definition
|
||||
const vert = flowDb.getVertices();
|
||||
const vert = diagObj.db.getVertices();
|
||||
|
||||
const edges = flowDb.getEdges();
|
||||
const edges = diagObj.db.getEdges();
|
||||
|
||||
log.info(edges);
|
||||
let i = 0;
|
||||
@ -435,18 +422,17 @@ export const draw = function (text, id) {
|
||||
g.setParent(subG.nodes[j], subG.id);
|
||||
}
|
||||
}
|
||||
addVertices(vert, g, id, root, doc);
|
||||
addEdges(edges, g);
|
||||
addVertices(vert, g, id, root, doc, diagObj);
|
||||
addEdges(edges, g, diagObj);
|
||||
|
||||
// Add custom shapes
|
||||
// flowChartShapes.addToRenderV2(addShape);
|
||||
|
||||
// Set up an SVG group so that we can translate the final graph.
|
||||
const svg = root.select(`[id="${id}"]`);
|
||||
svg.attr('xmlns:xlink', 'http://www.w3.org/1999/xlink');
|
||||
|
||||
// Adds title and description to the flow chart
|
||||
addSVGAccessibilityFields(parser.yy, svg, id);
|
||||
addSVGAccessibilityFields(diagObj.db, svg, id);
|
||||
|
||||
// Run the renderer. This is what draws the final graph.
|
||||
const element = root.select('#' + id + ' g');
|
||||
@ -455,7 +441,7 @@ export const draw = function (text, id) {
|
||||
setupGraphViewbox(g, svg, conf.diagramPadding, conf.useMaxWidth);
|
||||
|
||||
// Index nodes
|
||||
flowDb.indexNodes('subGraph' + i);
|
||||
diagObj.db.indexNodes('subGraph' + i);
|
||||
|
||||
// Add label rects for non html labels
|
||||
if (!conf.htmlLabels) {
|
||||
|
@ -1,10 +1,6 @@
|
||||
import graphlib from 'graphlib';
|
||||
import { select, curveLinear, selectAll } from 'd3';
|
||||
|
||||
import flowDb from './flowDb';
|
||||
import flow from './parser/flow';
|
||||
import { getConfig } from '../../config';
|
||||
|
||||
import dagreD3 from 'dagre-d3';
|
||||
import addHtmlLabel from 'dagre-d3/lib/label/add-html-label.js';
|
||||
import { log } from '../../logger';
|
||||
@ -30,8 +26,9 @@ export const setConf = function (cnf) {
|
||||
* @param root
|
||||
* @param doc
|
||||
* @param _doc
|
||||
* @param diagObj
|
||||
*/
|
||||
export const addVertices = function (vert, g, svgId, root, _doc) {
|
||||
export const addVertices = function (vert, g, svgId, root, _doc, diagObj) {
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
|
||||
const svg = !root ? select(`[id="${svgId}"]`) : root.select(`[id="${svgId}"]`);
|
||||
@ -144,7 +141,7 @@ export const addVertices = function (vert, g, svgId, root, _doc) {
|
||||
}
|
||||
// Add the node
|
||||
log.warn('Adding node', vertex.id, vertex.domId);
|
||||
g.setNode(flowDb.lookUpDomId(vertex.id), {
|
||||
g.setNode(diagObj.db.lookUpDomId(vertex.id), {
|
||||
labelType: 'svg',
|
||||
labelStyle: styles.labelStyle,
|
||||
shape: _shape,
|
||||
@ -153,7 +150,7 @@ export const addVertices = function (vert, g, svgId, root, _doc) {
|
||||
ry: radious,
|
||||
class: classStr,
|
||||
style: styles.style,
|
||||
id: flowDb.lookUpDomId(vertex.id),
|
||||
id: diagObj.db.lookUpDomId(vertex.id),
|
||||
});
|
||||
});
|
||||
};
|
||||
@ -163,8 +160,9 @@ export const addVertices = function (vert, g, svgId, root, _doc) {
|
||||
*
|
||||
* @param {object} edges The edges to add to the graph
|
||||
* @param {object} g The graph object
|
||||
* @param diagObj
|
||||
*/
|
||||
export const addEdges = function (edges, g) {
|
||||
export const addEdges = function (edges, g, diagObj) {
|
||||
let cnt = 0;
|
||||
|
||||
let defaultStyle;
|
||||
@ -264,7 +262,7 @@ export const addEdges = function (edges, g) {
|
||||
edgeData.minlen = edge.length || 1;
|
||||
|
||||
// Add the edge to the graph
|
||||
g.setEdge(flowDb.lookUpDomId(edge.start), flowDb.lookUpDomId(edge.end), edgeData, cnt);
|
||||
g.setEdge(diagObj.db.lookUpDomId(edge.start), diagObj.db.lookUpDomId(edge.end), edgeData, cnt);
|
||||
});
|
||||
};
|
||||
|
||||
@ -272,18 +270,16 @@ export const addEdges = function (edges, g) {
|
||||
* Returns the all the styles from classDef statements in the graph definition.
|
||||
*
|
||||
* @param text
|
||||
* @param diagObj
|
||||
* @returns {object} ClassDef styles
|
||||
*/
|
||||
export const getClasses = function (text) {
|
||||
export const getClasses = function (text, diagObj) {
|
||||
log.info('Extracting classes');
|
||||
flowDb.clear();
|
||||
diagObj.db.clear();
|
||||
try {
|
||||
const parser = flow.parser;
|
||||
parser.yy = flowDb;
|
||||
|
||||
// Parse the graph definition
|
||||
parser.parse(text);
|
||||
return flowDb.getClasses();
|
||||
diagObj.parse(text);
|
||||
return diagObj.db.getClasses();
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
@ -294,14 +290,12 @@ export const getClasses = function (text) {
|
||||
*
|
||||
* @param text
|
||||
* @param id
|
||||
* @param _version
|
||||
* @param diagObj
|
||||
*/
|
||||
export const draw = function (text, id) {
|
||||
export const draw = function (text, id, _version, diagObj) {
|
||||
log.info('Drawing flowchart');
|
||||
flowDb.clear();
|
||||
flowDb.setGen('gen-1');
|
||||
const parser = flow.parser;
|
||||
parser.yy = flowDb;
|
||||
|
||||
diagObj.db.clear();
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
@ -314,14 +308,14 @@ export const draw = function (text, id) {
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
// Parse the graph definition
|
||||
// try {
|
||||
parser.parse(text);
|
||||
// } catch (err) {
|
||||
// log.debug('Parsing failed');
|
||||
// }
|
||||
try {
|
||||
diagObj.parser.parse(text);
|
||||
} catch (err) {
|
||||
log.debug('Parsing failed');
|
||||
}
|
||||
|
||||
// Fetch the default direction, use TD if none was found
|
||||
let dir = flowDb.getDirection();
|
||||
let dir = diagObj.db.getDirection();
|
||||
if (typeof dir === 'undefined') {
|
||||
dir = 'TD';
|
||||
}
|
||||
@ -347,17 +341,17 @@ export const draw = function (text, id) {
|
||||
});
|
||||
|
||||
let subG;
|
||||
const subGraphs = flowDb.getSubGraphs();
|
||||
const subGraphs = diagObj.db.getSubGraphs();
|
||||
for (let i = subGraphs.length - 1; i >= 0; i--) {
|
||||
subG = subGraphs[i];
|
||||
flowDb.addVertex(subG.id, subG.title, 'group', undefined, subG.classes);
|
||||
diagObj.db.addVertex(subG.id, subG.title, 'group', undefined, subG.classes);
|
||||
}
|
||||
|
||||
// Fetch the vertices/nodes and edges/links from the parsed graph definition
|
||||
const vert = flowDb.getVertices();
|
||||
const vert = diagObj.db.getVertices();
|
||||
log.warn('Get vertices', vert);
|
||||
|
||||
const edges = flowDb.getEdges();
|
||||
const edges = diagObj.db.getEdges();
|
||||
|
||||
let i = 0;
|
||||
for (i = subGraphs.length - 1; i >= 0; i--) {
|
||||
@ -369,14 +363,14 @@ export const draw = function (text, id) {
|
||||
log.warn(
|
||||
'Setting subgraph',
|
||||
subG.nodes[j],
|
||||
flowDb.lookUpDomId(subG.nodes[j]),
|
||||
flowDb.lookUpDomId(subG.id)
|
||||
diagObj.db.lookUpDomId(subG.nodes[j]),
|
||||
diagObj.db.lookUpDomId(subG.id)
|
||||
);
|
||||
g.setParent(flowDb.lookUpDomId(subG.nodes[j]), flowDb.lookUpDomId(subG.id));
|
||||
g.setParent(diagObj.db.lookUpDomId(subG.nodes[j]), diagObj.db.lookUpDomId(subG.id));
|
||||
}
|
||||
}
|
||||
addVertices(vert, g, id, root, doc);
|
||||
addEdges(edges, g);
|
||||
addVertices(vert, g, id, root, doc, diagObj);
|
||||
addEdges(edges, g, diagObj);
|
||||
|
||||
// Create the renderer
|
||||
const Render = dagreD3.render;
|
||||
@ -425,31 +419,30 @@ export const draw = function (text, id) {
|
||||
|
||||
// Set up an SVG group so that we can translate the final graph.
|
||||
const svg = root.select(`[id="${id}"]`);
|
||||
svg.attr('xmlns:xlink', 'http://www.w3.org/1999/xlink');
|
||||
|
||||
// Adds title and description to the flow chart
|
||||
addSVGAccessibilityFields(parser.yy, svg, id);
|
||||
addSVGAccessibilityFields(diagObj.db, svg, id);
|
||||
|
||||
// Run the renderer. This is what draws the final graph.
|
||||
const element = root.select('#' + id + ' g');
|
||||
render(element, g);
|
||||
|
||||
element.selectAll('g.node').attr('title', function () {
|
||||
return flowDb.getTooltip(this.id);
|
||||
return diagObj.db.getTooltip(this.id);
|
||||
});
|
||||
|
||||
// Index nodes
|
||||
flowDb.indexNodes('subGraph' + i);
|
||||
diagObj.db.indexNodes('subGraph' + i);
|
||||
|
||||
// reposition labels
|
||||
for (i = 0; i < subGraphs.length; i++) {
|
||||
subG = subGraphs[i];
|
||||
if (subG.title !== 'undefined') {
|
||||
const clusterRects = doc.querySelectorAll(
|
||||
'#' + id + ' [id="' + flowDb.lookUpDomId(subG.id) + '"] rect'
|
||||
'#' + id + ' [id="' + diagObj.db.lookUpDomId(subG.id) + '"] rect'
|
||||
);
|
||||
const clusterEl = doc.querySelectorAll(
|
||||
'#' + id + ' [id="' + flowDb.lookUpDomId(subG.id) + '"]'
|
||||
'#' + id + ' [id="' + diagObj.db.lookUpDomId(subG.id) + '"]'
|
||||
);
|
||||
|
||||
const xPos = clusterRects[0].x.baseVal.value;
|
||||
@ -493,7 +486,7 @@ export const draw = function (text, id) {
|
||||
const vertex = vert[key];
|
||||
|
||||
if (vertex.link) {
|
||||
const node = root.select('#' + id + ' [id="' + flowDb.lookUpDomId(key) + '"]');
|
||||
const node = root.select('#' + id + ' [id="' + diagObj.db.lookUpDomId(key) + '"]');
|
||||
if (node) {
|
||||
const link = doc.createElementNS('http://www.w3.org/2000/svg', 'a');
|
||||
link.setAttributeNS('http://www.w3.org/2000/svg', 'class', vertex.classes.join(' '));
|
||||
|
@ -28,6 +28,13 @@ describe('the flowchart renderer', function () {
|
||||
['group', 'rect'],
|
||||
].forEach(function ([type, expectedShape, expectedRadios = 0]) {
|
||||
it(`should add the correct shaped node to the graph for vertex type ${type}`, function () {
|
||||
const fakeDiag = {
|
||||
db: {
|
||||
lookUpDomId: () => {
|
||||
return 'my-node-id';
|
||||
},
|
||||
},
|
||||
};
|
||||
const addedNodes = [];
|
||||
const mockG = {
|
||||
setNode: function (id, object) {
|
||||
@ -45,7 +52,10 @@ describe('the flowchart renderer', function () {
|
||||
},
|
||||
},
|
||||
mockG,
|
||||
'svg-id'
|
||||
'svg-id',
|
||||
undefined,
|
||||
undefined,
|
||||
fakeDiag
|
||||
);
|
||||
expect(addedNodes).toHaveLength(1);
|
||||
expect(addedNodes[0][0]).toEqual('my-node-id');
|
||||
@ -62,6 +72,13 @@ describe('the flowchart renderer', function () {
|
||||
) {
|
||||
it('should handle multiline texts with different line breaks', function () {
|
||||
const addedNodes = [];
|
||||
const fakeDiag = {
|
||||
db: {
|
||||
lookUpDomId: () => {
|
||||
return 'my-node-id';
|
||||
},
|
||||
},
|
||||
};
|
||||
const mockG = {
|
||||
setNode: function (id, object) {
|
||||
addedNodes.push([id, object]);
|
||||
@ -78,7 +95,10 @@ describe('the flowchart renderer', function () {
|
||||
},
|
||||
},
|
||||
mockG,
|
||||
'svg-id'
|
||||
'svg-id',
|
||||
false,
|
||||
document,
|
||||
fakeDiag
|
||||
);
|
||||
expect(addedNodes).toHaveLength(1);
|
||||
expect(addedNodes[0][0]).toEqual('my-node-id');
|
||||
@ -103,6 +123,13 @@ describe('the flowchart renderer', function () {
|
||||
].forEach(function ([style, expectedStyle, expectedLabelStyle]) {
|
||||
it(`should add the styles to style and/or labelStyle for style ${style}`, function () {
|
||||
const addedNodes = [];
|
||||
const fakeDiag = {
|
||||
db: {
|
||||
lookUpDomId: () => {
|
||||
return 'my-node-id';
|
||||
},
|
||||
},
|
||||
};
|
||||
const mockG = {
|
||||
setNode: function (id, object) {
|
||||
addedNodes.push([id, object]);
|
||||
@ -119,7 +146,10 @@ describe('the flowchart renderer', function () {
|
||||
},
|
||||
},
|
||||
mockG,
|
||||
'svg-id'
|
||||
'svg-id',
|
||||
undefined,
|
||||
undefined,
|
||||
fakeDiag
|
||||
);
|
||||
expect(addedNodes).toHaveLength(1);
|
||||
expect(addedNodes[0][0]).toEqual('my-node-id');
|
||||
@ -137,11 +167,18 @@ describe('the flowchart renderer', function () {
|
||||
addedNodes.push([id, object]);
|
||||
},
|
||||
};
|
||||
const fakeDiag = {
|
||||
db: {
|
||||
lookUpDomId: () => {
|
||||
return 'my-node-id';
|
||||
},
|
||||
},
|
||||
};
|
||||
addVertices(
|
||||
{
|
||||
v1: {
|
||||
type: 'rect',
|
||||
id: 'defaultNode',
|
||||
id: 'my-node-id',
|
||||
classes: [],
|
||||
styles: [],
|
||||
text: 'my vertex text',
|
||||
@ -155,12 +192,15 @@ describe('the flowchart renderer', function () {
|
||||
},
|
||||
},
|
||||
mockG,
|
||||
'svg-id'
|
||||
'svg-id',
|
||||
undefined,
|
||||
undefined,
|
||||
fakeDiag
|
||||
);
|
||||
expect(addedNodes).toHaveLength(2);
|
||||
expect(addedNodes[0][0]).toEqual('defaultNode');
|
||||
expect(addedNodes[0][0]).toEqual('my-node-id');
|
||||
expect(addedNodes[0][1]).toHaveProperty('class', 'default');
|
||||
expect(addedNodes[1][0]).toEqual('myNode');
|
||||
expect(addedNodes[1][0]).toEqual('my-node-id');
|
||||
expect(addedNodes[1][1]).toHaveProperty('class', 'myClass');
|
||||
});
|
||||
});
|
||||
@ -168,6 +208,13 @@ describe('the flowchart renderer', function () {
|
||||
describe('when adding edges to a graph', function () {
|
||||
it('should handle multiline texts and set centered label position', function () {
|
||||
const addedEdges = [];
|
||||
const fakeDiag = {
|
||||
db: {
|
||||
lookUpDomId: () => {
|
||||
return 'my-node-id';
|
||||
},
|
||||
},
|
||||
};
|
||||
const mockG = {
|
||||
setEdge: function (s, e, data, c) {
|
||||
addedEdges.push(data);
|
||||
@ -185,7 +232,7 @@ describe('the flowchart renderer', function () {
|
||||
{ style: ['stroke:DarkGray', 'stroke-width:2px'], text: 'Multi<br\t/>Line' },
|
||||
],
|
||||
mockG,
|
||||
'svg-id'
|
||||
fakeDiag
|
||||
);
|
||||
|
||||
addedEdges.forEach(function (edge) {
|
||||
@ -206,12 +253,19 @@ describe('the flowchart renderer', function () {
|
||||
].forEach(function ([style, expectedStyle, expectedLabelStyle]) {
|
||||
it(`should add the styles to style and/or labelStyle for style ${style}`, function () {
|
||||
const addedEdges = [];
|
||||
const fakeDiag = {
|
||||
db: {
|
||||
lookUpDomId: () => {
|
||||
return 'my-node-id';
|
||||
},
|
||||
},
|
||||
};
|
||||
const mockG = {
|
||||
setEdge: function (s, e, data, c) {
|
||||
addedEdges.push(data);
|
||||
},
|
||||
};
|
||||
addEdges([{ style: style, text: 'styling' }], mockG, 'svg-id');
|
||||
addEdges([{ style: style, text: 'styling' }], mockG, fakeDiag);
|
||||
|
||||
expect(addedEdges).toHaveLength(1);
|
||||
expect(addedEdges[0]).toHaveProperty('style', expectedStyle);
|
||||
|
@ -11,23 +11,20 @@ import {
|
||||
axisTop,
|
||||
timeFormat,
|
||||
} from 'd3';
|
||||
import { parser } from './parser/gantt';
|
||||
import common from '../common/common';
|
||||
import ganttDb from './ganttDb';
|
||||
import { getConfig } from '../../config';
|
||||
import { configureSvgSize } from '../../utils';
|
||||
import addSVGAccessibilityFields from '../../accessibility';
|
||||
|
||||
parser.yy = ganttDb;
|
||||
export const setConf = function () {
|
||||
log.debug('Something is calling, setConf, remove the call');
|
||||
};
|
||||
|
||||
let w;
|
||||
export const draw = function (text, id) {
|
||||
export const draw = function (text, id, version, diagObj) {
|
||||
const conf = getConfig().gantt;
|
||||
parser.yy.clear();
|
||||
parser.parse(text);
|
||||
// diagObj.db.clear();
|
||||
// parser.parse(text);
|
||||
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
// Handle root and Document for when rendering in sanbox mode
|
||||
@ -52,7 +49,7 @@ export const draw = function (text, id) {
|
||||
w = conf.useWidth;
|
||||
}
|
||||
|
||||
const taskArray = parser.yy.getTasks();
|
||||
const taskArray = diagObj.db.getTasks();
|
||||
|
||||
// Set height based on number of tasks
|
||||
const h = taskArray.length * (conf.barHeight + conf.barGap) + 2 * conf.topPadding;
|
||||
@ -109,12 +106,12 @@ export const draw = function (text, id) {
|
||||
|
||||
svg
|
||||
.append('text')
|
||||
.text(parser.yy.getDiagramTitle())
|
||||
.text(diagObj.db.getDiagramTitle())
|
||||
.attr('x', w / 2)
|
||||
.attr('y', conf.titleTopMargin)
|
||||
.attr('class', 'titleText');
|
||||
|
||||
addSVGAccessibilityFields(parser.yy, svg, id);
|
||||
addSVGAccessibilityFields(diagObj.db, svg, id);
|
||||
|
||||
/**
|
||||
* @param tasks
|
||||
@ -139,8 +136,8 @@ export const draw = function (text, id) {
|
||||
pageWidth,
|
||||
pageHeight,
|
||||
tasks,
|
||||
parser.yy.getExcludes(),
|
||||
parser.yy.getIncludes()
|
||||
diagObj.db.getExcludes(),
|
||||
diagObj.db.getIncludes()
|
||||
);
|
||||
makeGrid(leftPadding, topPadding, pageWidth, pageHeight);
|
||||
drawRects(tasks, gap, topPadding, leftPadding, barHeight, colorScale, pageWidth, pageHeight);
|
||||
@ -187,7 +184,7 @@ export const draw = function (text, id) {
|
||||
// Draw the rects representing the tasks
|
||||
const rectangles = svg.append('g').selectAll('rect').data(theArray).enter();
|
||||
|
||||
const links = ganttDb.getLinks();
|
||||
const links = diagObj.db.getLinks();
|
||||
|
||||
// Render the tasks with links
|
||||
// Render the other tasks
|
||||
@ -430,14 +427,14 @@ export const draw = function (text, id) {
|
||||
0
|
||||
);
|
||||
const maxTime = tasks.reduce((max, { endTime }) => (max ? Math.max(max, endTime) : endTime), 0);
|
||||
const dateFormat = parser.yy.getDateFormat();
|
||||
const dateFormat = diagObj.db.getDateFormat();
|
||||
if (!minTime || !maxTime) return;
|
||||
|
||||
const excludeRanges = [];
|
||||
let range = null;
|
||||
let d = moment(minTime);
|
||||
while (d.valueOf() <= maxTime) {
|
||||
if (parser.yy.isInvalidDate(d, dateFormat, excludes, includes)) {
|
||||
if (diagObj.db.isInvalidDate(d, dateFormat, excludes, includes)) {
|
||||
if (!range) {
|
||||
range = {
|
||||
start: d.clone(),
|
||||
@ -495,7 +492,7 @@ export const draw = function (text, id) {
|
||||
function makeGrid(theSidePad, theTopPad, w, h) {
|
||||
let bottomXAxis = axisBottom(timeScale)
|
||||
.tickSize(-h + theTopPad + conf.gridLineStartPadding)
|
||||
.tickFormat(timeFormat(parser.yy.getAxisFormat() || conf.axisFormat || '%Y-%m-%d'));
|
||||
.tickFormat(timeFormat(diagObj.db.getAxisFormat() || conf.axisFormat || '%Y-%m-%d'));
|
||||
|
||||
svg
|
||||
.append('g')
|
||||
@ -509,10 +506,10 @@ export const draw = function (text, id) {
|
||||
.attr('font-size', 10)
|
||||
.attr('dy', '1em');
|
||||
|
||||
if (ganttDb.topAxisEnabled() || conf.topAxis) {
|
||||
if (diagObj.db.topAxisEnabled() || conf.topAxis) {
|
||||
let topXAxis = axisTop(timeScale)
|
||||
.tickSize(-h + theTopPad + conf.gridLineStartPadding)
|
||||
.tickFormat(timeFormat(parser.yy.getAxisFormat() || conf.axisFormat || '%Y-%m-%d'));
|
||||
.tickFormat(timeFormat(diagObj.db.getAxisFormat() || conf.axisFormat || '%Y-%m-%d'));
|
||||
|
||||
svg
|
||||
.append('g')
|
||||
@ -592,7 +589,7 @@ export const draw = function (text, id) {
|
||||
* @param h
|
||||
*/
|
||||
function drawToday(theSidePad, theTopPad, w, h) {
|
||||
const todayMarker = ganttDb.getTodayMarker();
|
||||
const todayMarker = diagObj.db.getTodayMarker();
|
||||
if (todayMarker === 'off') {
|
||||
return;
|
||||
}
|
||||
|
8
src/diagrams/git/gitGraphDetector.js
Normal file
8
src/diagrams/git/gitGraphDetector.js
Normal file
@ -0,0 +1,8 @@
|
||||
const detector = (txt) => {
|
||||
if (txt.match(/^\s*gitGraph/)) {
|
||||
return 'gitGraph';
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export default detector;
|
@ -1,7 +1,5 @@
|
||||
import { curveBasis, line, select } from 'd3';
|
||||
import { interpolateToCurve, getStylesFromArray, configureSvgSize } from '../../utils';
|
||||
import db from './gitGraphAst';
|
||||
import gitGraphParser from './parser/gitGraph';
|
||||
import { select } from 'd3';
|
||||
import { configureSvgSize } from '../../utils';
|
||||
import { log } from '../../logger';
|
||||
import { getConfig } from '../../config';
|
||||
import addSVGAccessibilityFields from '../../accessibility';
|
||||
@ -17,6 +15,8 @@ const commitType = {
|
||||
CHERRY_PICK: 4,
|
||||
};
|
||||
|
||||
const THEME_COLOR_LIMIT = 8;
|
||||
|
||||
let branchPos = {};
|
||||
let commitPos = {};
|
||||
let lanes = [];
|
||||
@ -119,13 +119,9 @@ const drawCommits = (svg, commits, modifyGraph) => {
|
||||
circle.attr('width', 20);
|
||||
circle.attr(
|
||||
'class',
|
||||
'commit ' +
|
||||
commit.id +
|
||||
' commit-highlight' +
|
||||
branchPos[commit.branch].index +
|
||||
' ' +
|
||||
typeClass +
|
||||
'-outer'
|
||||
`commit ${commit.id} commit-highlight${
|
||||
branchPos[commit.branch].index % THEME_COLOR_LIMIT
|
||||
} ${typeClass}-outer`
|
||||
);
|
||||
gBullets
|
||||
.append('rect')
|
||||
@ -135,13 +131,9 @@ const drawCommits = (svg, commits, modifyGraph) => {
|
||||
.attr('width', 12)
|
||||
.attr(
|
||||
'class',
|
||||
'commit ' +
|
||||
commit.id +
|
||||
' commit' +
|
||||
branchPos[commit.branch].index +
|
||||
' ' +
|
||||
typeClass +
|
||||
'-inner'
|
||||
`commit ${commit.id} commit${
|
||||
branchPos[commit.branch].index % THEME_COLOR_LIMIT
|
||||
} ${typeClass}-inner`
|
||||
);
|
||||
} else if (commit.type === commitType.CHERRY_PICK) {
|
||||
gBullets
|
||||
@ -149,21 +141,21 @@ const drawCommits = (svg, commits, modifyGraph) => {
|
||||
.attr('cx', x)
|
||||
.attr('cy', y)
|
||||
.attr('r', 10)
|
||||
.attr('class', 'commit ' + commit.id + ' ' + typeClass);
|
||||
.attr('class', `commit ${commit.id} ${typeClass}`);
|
||||
gBullets
|
||||
.append('circle')
|
||||
.attr('cx', x - 3)
|
||||
.attr('cy', y + 2)
|
||||
.attr('r', 2.75)
|
||||
.attr('fill', '#fff')
|
||||
.attr('class', 'commit ' + commit.id + ' ' + typeClass);
|
||||
.attr('class', `commit ${commit.id} ${typeClass}`);
|
||||
gBullets
|
||||
.append('circle')
|
||||
.attr('cx', x + 3)
|
||||
.attr('cy', y + 2)
|
||||
.attr('r', 2.75)
|
||||
.attr('fill', '#fff')
|
||||
.attr('class', 'commit ' + commit.id + ' ' + typeClass);
|
||||
.attr('class', `commit ${commit.id} ${typeClass}`);
|
||||
gBullets
|
||||
.append('line')
|
||||
.attr('x1', x + 3)
|
||||
@ -171,7 +163,7 @@ const drawCommits = (svg, commits, modifyGraph) => {
|
||||
.attr('x2', x)
|
||||
.attr('y2', y - 5)
|
||||
.attr('stroke', '#fff')
|
||||
.attr('class', 'commit ' + commit.id + ' ' + typeClass);
|
||||
.attr('class', `commit ${commit.id} ${typeClass}`);
|
||||
gBullets
|
||||
.append('line')
|
||||
.attr('x1', x - 3)
|
||||
@ -179,13 +171,16 @@ const drawCommits = (svg, commits, modifyGraph) => {
|
||||
.attr('x2', x)
|
||||
.attr('y2', y - 5)
|
||||
.attr('stroke', '#fff')
|
||||
.attr('class', 'commit ' + commit.id + ' ' + typeClass);
|
||||
.attr('class', `commit ${commit.id} ${typeClass}`);
|
||||
} else {
|
||||
const circle = gBullets.append('circle');
|
||||
circle.attr('cx', x);
|
||||
circle.attr('cy', y);
|
||||
circle.attr('r', commit.type === commitType.MERGE ? 9 : 10);
|
||||
circle.attr('class', 'commit ' + commit.id + ' commit' + branchPos[commit.branch].index);
|
||||
circle.attr(
|
||||
'class',
|
||||
`commit ${commit.id} commit${branchPos[commit.branch].index % THEME_COLOR_LIMIT}`
|
||||
);
|
||||
if (commit.type === commitType.MERGE) {
|
||||
const circle2 = gBullets.append('circle');
|
||||
circle2.attr('cx', x);
|
||||
@ -193,7 +188,9 @@ const drawCommits = (svg, commits, modifyGraph) => {
|
||||
circle2.attr('r', 6);
|
||||
circle2.attr(
|
||||
'class',
|
||||
'commit ' + typeClass + ' ' + commit.id + ' commit' + branchPos[commit.branch].index
|
||||
`commit ${typeClass} ${commit.id} commit${
|
||||
branchPos[commit.branch].index % THEME_COLOR_LIMIT
|
||||
}`
|
||||
);
|
||||
}
|
||||
if (commit.type === commitType.REVERSE) {
|
||||
@ -202,7 +199,9 @@ const drawCommits = (svg, commits, modifyGraph) => {
|
||||
.attr('d', `M ${x - 5},${y - 5}L${x + 5},${y + 5}M${x - 5},${y + 5}L${x + 5},${y - 5}`)
|
||||
.attr(
|
||||
'class',
|
||||
'commit ' + typeClass + ' ' + commit.id + ' commit' + branchPos[commit.branch].index
|
||||
`commit ${typeClass} ${commit.id} commit${
|
||||
branchPos[commit.branch].index % THEME_COLOR_LIMIT
|
||||
}`
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -432,7 +431,7 @@ const drawArrow = (svg, commit1, commit2, allCommits) => {
|
||||
const arrow = svg
|
||||
.append('path')
|
||||
.attr('d', lineDef)
|
||||
.attr('class', 'arrow arrow' + colorClassNum);
|
||||
.attr('class', 'arrow arrow' + (colorClassNum % THEME_COLOR_LIMIT));
|
||||
};
|
||||
|
||||
const drawArrows = (svg, commits) => {
|
||||
@ -462,7 +461,7 @@ const drawBranches = (svg, branches) => {
|
||||
const gitGraphConfig = getConfig().gitGraph;
|
||||
const g = svg.append('g');
|
||||
branches.forEach((branch, index) => {
|
||||
let adjustIndexForTheme = index >= 8 ? index - 8 : index;
|
||||
const adjustIndexForTheme = index % THEME_COLOR_LIMIT;
|
||||
|
||||
const pos = branchPos[branch.name].pos;
|
||||
const line = g.append('line');
|
||||
@ -515,23 +514,17 @@ const drawBranches = (svg, branches) => {
|
||||
* @param txt
|
||||
* @param id
|
||||
* @param ver
|
||||
* @param diagObj
|
||||
*/
|
||||
export const draw = function (txt, id, ver) {
|
||||
export const draw = function (txt, id, ver, diagObj) {
|
||||
clear();
|
||||
const conf = getConfig();
|
||||
const gitGraphConfig = getConfig().gitGraph;
|
||||
// try {
|
||||
const parser = gitGraphParser.parser;
|
||||
parser.yy = db;
|
||||
parser.yy.clear();
|
||||
|
||||
log.debug('in gitgraph renderer', txt + '\n', 'id:', id, ver);
|
||||
// // Parse the graph definition
|
||||
parser.parse(txt + '\n');
|
||||
|
||||
const direction = db.getDirection();
|
||||
allCommitsDict = db.getCommits();
|
||||
const branches = db.getBranchesAsObjArray();
|
||||
allCommitsDict = diagObj.db.getCommits();
|
||||
const branches = diagObj.db.getBranchesAsObjArray();
|
||||
|
||||
// Position branches vertically
|
||||
let pos = 0;
|
||||
@ -543,7 +536,7 @@ export const draw = function (txt, id, ver) {
|
||||
const diagram = select(`[id="${id}"]`);
|
||||
|
||||
// Adds title and description to the flow chart
|
||||
addSVGAccessibilityFields(parser.yy, diagram, id);
|
||||
addSVGAccessibilityFields(diagObj.db, diagram, id);
|
||||
|
||||
drawCommits(diagram, allCommitsDict, false);
|
||||
if (gitGraphConfig.showBranches) {
|
||||
|
@ -1,30 +1,20 @@
|
||||
/** Created by knut on 14-12-11. */
|
||||
import { select } from 'd3';
|
||||
import db from './infoDb';
|
||||
import infoParser from './parser/info';
|
||||
import { log } from '../../logger';
|
||||
import { getConfig } from '../../config';
|
||||
|
||||
const conf = {};
|
||||
export const setConf = function (cnf) {
|
||||
const keys = Object.keys(cnf);
|
||||
|
||||
keys.forEach(function (key) {
|
||||
conf[key] = cnf[key];
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Draws a an info picture in the tag with id: id based on the graph definition in text.
|
||||
*
|
||||
* @param {any} text
|
||||
* @param {any} id
|
||||
* @param {any} version
|
||||
* @param diagObj
|
||||
*/
|
||||
export const draw = (text, id, version) => {
|
||||
export const draw = (text, id, version, diagObj) => {
|
||||
try {
|
||||
const parser = infoParser.parser;
|
||||
parser.yy = db;
|
||||
// const parser = infoParser.parser;
|
||||
// parser.yy = db;
|
||||
log.debug('Renering info diagram\n' + text);
|
||||
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
@ -40,8 +30,8 @@ export const draw = (text, id, version) => {
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
// Parse the graph definition
|
||||
parser.parse(text);
|
||||
log.debug('Parsed info diagram');
|
||||
// parser.parse(text);
|
||||
// log.debug('Parsed info diagram');
|
||||
// Fetch the default direction, use TD if none was found
|
||||
const svg = root.select('#' + id);
|
||||
|
||||
@ -65,6 +55,5 @@ export const draw = (text, id, version) => {
|
||||
};
|
||||
|
||||
export default {
|
||||
setConf,
|
||||
draw,
|
||||
};
|
||||
|
14
src/diagrams/mindmap/info.spc.js
Normal file
14
src/diagrams/mindmap/info.spc.js
Normal file
@ -0,0 +1,14 @@
|
||||
describe('when parsing an info graph it', function () {
|
||||
var ex;
|
||||
beforeEach(function () {
|
||||
ex = require('./parser/info').parser;
|
||||
ex.yy = require('./infoDb');
|
||||
});
|
||||
|
||||
it('should handle an info definition', function () {
|
||||
var str = `info
|
||||
showInfo`;
|
||||
|
||||
ex.parse(str);
|
||||
});
|
||||
});
|
34
src/diagrams/mindmap/infoDb.js
Normal file
34
src/diagrams/mindmap/infoDb.js
Normal file
@ -0,0 +1,34 @@
|
||||
/** Created by knut on 15-01-14. */
|
||||
import { log } from '../../logger';
|
||||
|
||||
var message = '';
|
||||
var info = false;
|
||||
|
||||
export const setMessage = (txt) => {
|
||||
log.debug('Setting message to: ' + txt);
|
||||
message = txt;
|
||||
};
|
||||
|
||||
export const getMessage = () => {
|
||||
return message;
|
||||
};
|
||||
|
||||
export const setInfo = (inf) => {
|
||||
info = inf;
|
||||
};
|
||||
|
||||
export const getInfo = () => {
|
||||
return info;
|
||||
};
|
||||
|
||||
// export const parseError = (err, hash) => {
|
||||
// global.mermaidAPI.parseError(err, hash)
|
||||
// }
|
||||
|
||||
export default {
|
||||
setMessage,
|
||||
getMessage,
|
||||
setInfo,
|
||||
getInfo,
|
||||
// parseError
|
||||
};
|
59
src/diagrams/mindmap/infoRenderer.js
Normal file
59
src/diagrams/mindmap/infoRenderer.js
Normal file
@ -0,0 +1,59 @@
|
||||
/** Created by knut on 14-12-11. */
|
||||
import { select } from 'd3';
|
||||
import { log } from '../../logger';
|
||||
import { getConfig } from '../../config';
|
||||
|
||||
/**
|
||||
* Draws a an info picture in the tag with id: id based on the graph definition in text.
|
||||
*
|
||||
* @param {any} text
|
||||
* @param {any} id
|
||||
* @param {any} version
|
||||
* @param diagObj
|
||||
*/
|
||||
export const draw = (text, id, version, diagObj) => {
|
||||
try {
|
||||
// const parser = infoParser.parser;
|
||||
// parser.yy = db;
|
||||
log.debug('Renering info diagram\n' + text);
|
||||
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
// Handle root and Document for when rendering in sanbox mode
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
// Parse the graph definition
|
||||
// parser.parse(text);
|
||||
// log.debug('Parsed info diagram');
|
||||
// Fetch the default direction, use TD if none was found
|
||||
const svg = root.select('#' + id);
|
||||
|
||||
const g = svg.append('g');
|
||||
|
||||
g.append('text') // text label for the x axis
|
||||
.attr('x', 100)
|
||||
.attr('y', 40)
|
||||
.attr('class', 'version')
|
||||
.attr('font-size', '32px')
|
||||
.style('text-anchor', 'middle')
|
||||
.text('v ' + version);
|
||||
|
||||
svg.attr('height', 100);
|
||||
svg.attr('width', 400);
|
||||
// svg.attr('viewBox', '0 0 300 150');
|
||||
} catch (e) {
|
||||
log.error('Error while rendering info diagram');
|
||||
log.error(e.message);
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
draw,
|
||||
};
|
8
src/diagrams/mindmap/mindamapDetector.js
Normal file
8
src/diagrams/mindmap/mindamapDetector.js
Normal file
@ -0,0 +1,8 @@
|
||||
const detector = (txt) => {
|
||||
if (txt.match(/^\s*mindmap/)) {
|
||||
return 'mindmap';
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export default detector;
|
48
src/diagrams/mindmap/parser/mindamap.jison
Normal file
48
src/diagrams/mindmap/parser/mindamap.jison
Normal file
@ -0,0 +1,48 @@
|
||||
/** mermaid
|
||||
* https://knsv.github.io/mermaid
|
||||
* (c) 2015 Knut Sveidqvist
|
||||
* MIT license.
|
||||
*/
|
||||
%lex
|
||||
|
||||
%options case-insensitive
|
||||
|
||||
%{
|
||||
// Pre-lexer code can go here
|
||||
%}
|
||||
|
||||
%%
|
||||
|
||||
"info" return 'info' ;
|
||||
[\s\n\r]+ return 'NL' ;
|
||||
[\s]+ return 'space';
|
||||
"showInfo" return 'showInfo';
|
||||
<<EOF>> return 'EOF' ;
|
||||
. return 'TXT' ;
|
||||
|
||||
/lex
|
||||
|
||||
%start start
|
||||
|
||||
%% /* language grammar */
|
||||
|
||||
start
|
||||
// %{ : info document 'EOF' { return yy; } }
|
||||
: info document 'EOF' { return yy; }
|
||||
;
|
||||
|
||||
document
|
||||
: /* empty */
|
||||
| document line
|
||||
;
|
||||
|
||||
line
|
||||
: statement { }
|
||||
| 'NL'
|
||||
;
|
||||
|
||||
statement
|
||||
: showInfo { yy.setInfo(true); }
|
||||
;
|
||||
|
||||
%%
|
3
src/diagrams/mindmap/styles.js
Normal file
3
src/diagrams/mindmap/styles.js
Normal file
@ -0,0 +1,3 @@
|
||||
const getStyles = () => ``;
|
||||
|
||||
export default getStyles;
|
@ -1,7 +1,5 @@
|
||||
/** Created by AshishJ on 11-09-2019. */
|
||||
import { select, scaleOrdinal, pie as d3pie, arc } from 'd3';
|
||||
import pieData from './pieDb';
|
||||
import pieParser from './parser/pie';
|
||||
import { log } from '../../logger';
|
||||
import { configureSvgSize } from '../../utils';
|
||||
import * as configApi from '../../config';
|
||||
@ -17,11 +15,9 @@ let conf = configApi.getConfig();
|
||||
*/
|
||||
let width;
|
||||
const height = 450;
|
||||
export const draw = (txt, id) => {
|
||||
export const draw = (txt, id, _version, diagObj) => {
|
||||
try {
|
||||
conf = configApi.getConfig();
|
||||
const parser = pieParser.parser;
|
||||
parser.yy = pieData;
|
||||
log.debug('Rendering info diagram\n' + txt);
|
||||
|
||||
const securityLevel = configApi.getConfig().securityLevel;
|
||||
@ -37,8 +33,8 @@ export const draw = (txt, id) => {
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
// Parse the Pie Chart definition
|
||||
parser.yy.clear();
|
||||
parser.parse(txt);
|
||||
diagObj.db.clear();
|
||||
diagObj.parser.parse(txt);
|
||||
log.debug('Parsed info diagram');
|
||||
const elem = doc.getElementById(id);
|
||||
width = elem.parentElement.offsetWidth;
|
||||
@ -57,7 +53,7 @@ export const draw = (txt, id) => {
|
||||
const diagram = root.select('#' + id);
|
||||
configureSvgSize(diagram, height, width, conf.pie.useMaxWidth);
|
||||
|
||||
addSVGAccessibilityFields(parser.yy, diagram, id);
|
||||
addSVGAccessibilityFields(diagObj.db, diagram, id);
|
||||
// Set viewBox
|
||||
elem.setAttribute('viewBox', '0 0 ' + width + ' ' + height);
|
||||
|
||||
@ -72,7 +68,7 @@ export const draw = (txt, id) => {
|
||||
.append('g')
|
||||
.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
|
||||
|
||||
var data = pieData.getSections();
|
||||
var data = diagObj.db.getSections();
|
||||
var sum = 0;
|
||||
Object.keys(data).forEach(function (key) {
|
||||
sum += data[key];
|
||||
@ -136,7 +132,7 @@ export const draw = (txt, id) => {
|
||||
|
||||
svg
|
||||
.append('text')
|
||||
.text(parser.yy.getDiagramTitle())
|
||||
.text(diagObj.db.getDiagramTitle())
|
||||
.attr('x', 0)
|
||||
.attr('y', -(height - 50) / 2)
|
||||
.attr('class', 'pieTitleText');
|
||||
@ -169,7 +165,7 @@ export const draw = (txt, id) => {
|
||||
.attr('x', legendRectSize + legendSpacing)
|
||||
.attr('y', legendRectSize - legendSpacing)
|
||||
.text(function (d) {
|
||||
if (parser.yy.getShowData() || conf.showData || conf.pie.showData) {
|
||||
if (diagObj.db.getShowData() || conf.showData || conf.pie.showData) {
|
||||
return d.data[0] + ' [' + d.data[1] + ']';
|
||||
} else {
|
||||
return d.data[0];
|
||||
|
@ -1,29 +1,16 @@
|
||||
import { line, select } from 'd3';
|
||||
import dagre from 'dagre';
|
||||
import graphlib from 'graphlib';
|
||||
// import * as configApi from '../../config';
|
||||
import { log } from '../../logger';
|
||||
import { configureSvgSize } from '../../utils';
|
||||
import common from '../common/common';
|
||||
import { parser } from './parser/requirementDiagram';
|
||||
import requirementDb from './requirementDb';
|
||||
import markers from './requirementMarkers';
|
||||
import { getConfig } from '../../config';
|
||||
import addSVGAccessibilityFields from '../../accessibility';
|
||||
|
||||
const conf = {};
|
||||
let conf = {};
|
||||
let relCnt = 0;
|
||||
|
||||
export const setConf = function (cnf) {
|
||||
if (typeof cnf === 'undefined') {
|
||||
return;
|
||||
}
|
||||
const keys = Object.keys(cnf);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
conf[keys[i]] = cnf[keys[i]];
|
||||
}
|
||||
};
|
||||
|
||||
const newRectNode = (parentNode, id) => {
|
||||
return parentNode
|
||||
.insert('rect', '#' + id)
|
||||
@ -162,7 +149,7 @@ const addEdgeLabel = (parentNode, svgPath, conf, txt) => {
|
||||
.attr('fill-opacity', '85%');
|
||||
};
|
||||
|
||||
const drawRelationshipFromLayout = function (svg, rel, g, insert) {
|
||||
const drawRelationshipFromLayout = function (svg, rel, g, insert, diagObj) {
|
||||
// Find the edge relating to this relationship
|
||||
const edge = g.edge(elementString(rel.src), elementString(rel.dst));
|
||||
|
||||
@ -182,7 +169,7 @@ const drawRelationshipFromLayout = function (svg, rel, g, insert) {
|
||||
.attr('d', lineFunction(edge.points))
|
||||
.attr('fill', 'none');
|
||||
|
||||
if (rel.type == requirementDb.Relationships.CONTAINS) {
|
||||
if (rel.type == diagObj.db.Relationships.CONTAINS) {
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + common.getUrl(conf.arrowMarkerAbsolute) + '#' + rel.type + '_line_ending' + ')'
|
||||
@ -318,12 +305,12 @@ const elementString = (str) => {
|
||||
return str.replace(/\s/g, '').replace(/\./g, '_');
|
||||
};
|
||||
|
||||
export const draw = (text, id) => {
|
||||
parser.yy = requirementDb;
|
||||
parser.yy.clear();
|
||||
parser.parse(text);
|
||||
export const draw = (text, id, _version, diagObj) => {
|
||||
conf = getConfig().requirement;
|
||||
diagObj.db.clear();
|
||||
diagObj.parser.parse(text);
|
||||
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
const securityLevel = conf.securityLevel;
|
||||
// Handle root and Document for when rendering in sanbox mode
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
@ -355,9 +342,9 @@ export const draw = (text, id) => {
|
||||
return {};
|
||||
});
|
||||
|
||||
let requirements = requirementDb.getRequirements();
|
||||
let elements = requirementDb.getElements();
|
||||
let relationships = requirementDb.getRelationships();
|
||||
let requirements = diagObj.db.getRequirements();
|
||||
let elements = diagObj.db.getElements();
|
||||
let relationships = diagObj.db.getRelationships();
|
||||
|
||||
drawReqs(requirements, g, svg);
|
||||
drawElements(elements, g, svg);
|
||||
@ -366,10 +353,9 @@ export const draw = (text, id) => {
|
||||
adjustEntities(svg, g);
|
||||
|
||||
relationships.forEach(function (rel) {
|
||||
drawRelationshipFromLayout(svg, rel, g, id);
|
||||
drawRelationshipFromLayout(svg, rel, g, id, diagObj);
|
||||
});
|
||||
|
||||
// svg.attr('height', '500px');
|
||||
const padding = conf.rect_padding;
|
||||
const svgBounds = svg.node().getBBox();
|
||||
const width = svgBounds.width + padding * 2;
|
||||
@ -379,10 +365,9 @@ export const draw = (text, id) => {
|
||||
|
||||
svg.attr('viewBox', `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`);
|
||||
// Adds title and description to the requirements diagram
|
||||
addSVGAccessibilityFields(parser.yy, svg, id);
|
||||
addSVGAccessibilityFields(diagObj.db, svg, id);
|
||||
};
|
||||
|
||||
export default {
|
||||
setConf,
|
||||
draw,
|
||||
};
|
||||
|
@ -19,7 +19,7 @@ const notes = [];
|
||||
let diagramTitle = '';
|
||||
let description = '';
|
||||
let sequenceNumbersEnabled = false;
|
||||
let wrapEnabled = false;
|
||||
let wrapEnabled;
|
||||
|
||||
export const parseDirective = function (statement, context, type) {
|
||||
mermaidAPI.parseDirective(this, statement, context, type);
|
||||
@ -140,7 +140,14 @@ export const setWrap = function (wrapSetting) {
|
||||
wrapEnabled = wrapSetting;
|
||||
};
|
||||
|
||||
export const autoWrap = () => wrapEnabled;
|
||||
export const autoWrap = () => {
|
||||
// if setWrap has been called, use that value, otherwise use the value from the config
|
||||
// TODO: refactor, always use the config value let setWrap update the config value
|
||||
if (typeof wrapEnabled !== 'undefined') {
|
||||
return wrapEnabled;
|
||||
}
|
||||
return configApi.getConfig().sequence.wrap;
|
||||
};
|
||||
|
||||
export const clear = function () {
|
||||
actors = {};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,15 +1,14 @@
|
||||
import { select, selectAll } from 'd3';
|
||||
import svgDraw, { drawText, fixLifeLineHeights } from './svgDraw';
|
||||
import { log } from '../../logger';
|
||||
import { parser } from './parser/sequenceDiagram';
|
||||
// import { parser } from './parser/sequenceDiagram';
|
||||
import common from '../common/common';
|
||||
import sequenceDb from './sequenceDb';
|
||||
// import sequenceDb from './sequenceDb';
|
||||
import * as configApi from '../../config';
|
||||
import utils, { assignWithDepth, configureSvgSize } from '../../utils';
|
||||
import assignWithDepth from '../../assignWithDepth';
|
||||
import utils, { configureSvgSize } from '../../utils';
|
||||
import addSVGAccessibilityFields from '../../accessibility';
|
||||
|
||||
parser.yy = sequenceDb;
|
||||
|
||||
let conf = {};
|
||||
|
||||
export const bounds = {
|
||||
@ -86,7 +85,7 @@ export const bounds = {
|
||||
stopy: undefined,
|
||||
};
|
||||
this.verticalPos = 0;
|
||||
setConf(parser.yy.getConfig());
|
||||
setConf(configApi.getConfig());
|
||||
},
|
||||
updateVal: function (obj, key, val, fun) {
|
||||
if (typeof obj[key] === 'undefined') {
|
||||
@ -230,7 +229,7 @@ const drawNote = function (elem, noteModel) {
|
||||
textObj.fontWeight = conf.noteFontWeight;
|
||||
textObj.anchor = conf.noteAlign;
|
||||
textObj.textMargin = conf.noteMargin;
|
||||
textObj.valign = conf.noteAlign;
|
||||
textObj.valign = 'center';
|
||||
|
||||
let textElem = drawText(g, textObj);
|
||||
|
||||
@ -327,8 +326,9 @@ const boundMessage = function (diagram, msgModel) {
|
||||
* @param {any} diagram - The parent of the message element
|
||||
* @param {any} msgModel - The model containing fields describing a message
|
||||
* @param {float} lineStarty - The Y coordinate at which the message line starts
|
||||
* @param diagObj
|
||||
*/
|
||||
const drawMessage = function (diagram, msgModel, lineStarty) {
|
||||
const drawMessage = function (diagram, msgModel, lineStarty, diagObj) {
|
||||
const { startx, stopx, starty, message, type, sequenceIndex, sequenceVisible } = msgModel;
|
||||
let textDims = utils.calculateTextDimensions(message, messageFont(conf));
|
||||
const textObj = svgDraw.getTextObj();
|
||||
@ -342,7 +342,7 @@ const drawMessage = function (diagram, msgModel, lineStarty) {
|
||||
textObj.fontSize = conf.messageFontSize;
|
||||
textObj.fontWeight = conf.messageFontWeight;
|
||||
textObj.anchor = conf.messageAlign;
|
||||
textObj.valign = conf.messageAlign;
|
||||
textObj.valign = 'center';
|
||||
textObj.textMargin = conf.wrapPadding;
|
||||
textObj.tspan = false;
|
||||
|
||||
@ -394,10 +394,10 @@ const drawMessage = function (diagram, msgModel, lineStarty) {
|
||||
// Make an SVG Container
|
||||
// Draw the line
|
||||
if (
|
||||
type === parser.yy.LINETYPE.DOTTED ||
|
||||
type === parser.yy.LINETYPE.DOTTED_CROSS ||
|
||||
type === parser.yy.LINETYPE.DOTTED_POINT ||
|
||||
type === parser.yy.LINETYPE.DOTTED_OPEN
|
||||
type === diagObj.db.LINETYPE.DOTTED ||
|
||||
type === diagObj.db.LINETYPE.DOTTED_CROSS ||
|
||||
type === diagObj.db.LINETYPE.DOTTED_POINT ||
|
||||
type === diagObj.db.LINETYPE.DOTTED_OPEN
|
||||
) {
|
||||
line.style('stroke-dasharray', '3, 3');
|
||||
line.attr('class', 'messageLine1');
|
||||
@ -420,14 +420,14 @@ const drawMessage = function (diagram, msgModel, lineStarty) {
|
||||
line.attr('stroke-width', 2);
|
||||
line.attr('stroke', 'none'); // handled by theme/css anyway
|
||||
line.style('fill', 'none'); // remove any fill colour
|
||||
if (type === parser.yy.LINETYPE.SOLID || type === parser.yy.LINETYPE.DOTTED) {
|
||||
if (type === diagObj.db.LINETYPE.SOLID || type === diagObj.db.LINETYPE.DOTTED) {
|
||||
line.attr('marker-end', 'url(' + url + '#arrowhead)');
|
||||
}
|
||||
if (type === parser.yy.LINETYPE.SOLID_POINT || type === parser.yy.LINETYPE.DOTTED_POINT) {
|
||||
if (type === diagObj.db.LINETYPE.SOLID_POINT || type === diagObj.db.LINETYPE.DOTTED_POINT) {
|
||||
line.attr('marker-end', 'url(' + url + '#filled-head)');
|
||||
}
|
||||
|
||||
if (type === parser.yy.LINETYPE.SOLID_CROSS || type === parser.yy.LINETYPE.DOTTED_CROSS) {
|
||||
if (type === diagObj.db.LINETYPE.SOLID_CROSS || type === diagObj.db.LINETYPE.DOTTED_CROSS) {
|
||||
line.attr('marker-end', 'url(' + url + '#crosshead)');
|
||||
}
|
||||
|
||||
@ -581,10 +581,13 @@ function adjustLoopHeightForWrap(loopWidths, msg, preMargin, postMargin, addLoop
|
||||
/**
|
||||
* Draws a sequenceDiagram in the tag with id: id based on the graph definition in text.
|
||||
*
|
||||
* @param {any} text
|
||||
* @param {any} id
|
||||
* @param {any} text The text of the diagram
|
||||
* @param _text
|
||||
* @param {any} id The id of the diagram which will be used as a DOM element id¨
|
||||
* @param {any} _version Mermaid version from package.json
|
||||
* @param {any} diagObj A stanard diagram containing the db and the text and type etc of the diagram
|
||||
*/
|
||||
export const draw = function (text, id) {
|
||||
export const draw = function (_text, id, _version, diagObj) {
|
||||
conf = configApi.getConfig().sequence;
|
||||
const securityLevel = configApi.getConfig().securityLevel;
|
||||
// Handle root and Document for when rendering in sanbox mode
|
||||
@ -592,28 +595,25 @@ export const draw = function (text, id) {
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
}
|
||||
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
parser.yy.clear();
|
||||
parser.yy.setWrap(conf.wrap);
|
||||
parser.parse(text + '\n');
|
||||
bounds.init();
|
||||
log.debug(`C:${JSON.stringify(conf, null, 2)}`);
|
||||
log.debug(diagObj.db);
|
||||
|
||||
const diagram =
|
||||
securityLevel === 'sandbox' ? root.select(`[id="${id}"]`) : select(`[id="${id}"]`);
|
||||
|
||||
// Fetch data from the parsing
|
||||
const actors = parser.yy.getActors();
|
||||
const actorKeys = parser.yy.getActorKeys();
|
||||
const messages = parser.yy.getMessages();
|
||||
const title = parser.yy.getDiagramTitle();
|
||||
const actors = diagObj.db.getActors();
|
||||
const actorKeys = diagObj.db.getActorKeys();
|
||||
const messages = diagObj.db.getMessages();
|
||||
const title = diagObj.db.getDiagramTitle();
|
||||
|
||||
const maxMessageWidthPerActor = getMaxMessageWidthPerActor(actors, messages);
|
||||
const maxMessageWidthPerActor = getMaxMessageWidthPerActor(actors, messages, diagObj);
|
||||
conf.height = calculateActorMargins(actors, maxMessageWidthPerActor);
|
||||
|
||||
svgDraw.insertComputerIcon(diagram);
|
||||
@ -621,7 +621,7 @@ export const draw = function (text, id) {
|
||||
svgDraw.insertClockIcon(diagram);
|
||||
|
||||
drawActors(diagram, actors, actorKeys, 0, conf, messages);
|
||||
const loopWidths = calculateLoopBounds(messages, actors, maxMessageWidthPerActor);
|
||||
const loopWidths = calculateLoopBounds(messages, actors, maxMessageWidthPerActor, diagObj);
|
||||
|
||||
// The arrow head definition is attached to the svg once
|
||||
svgDraw.insertArrowHead(diagram);
|
||||
@ -658,17 +658,17 @@ export const draw = function (text, id) {
|
||||
let loopModel, noteModel, msgModel;
|
||||
|
||||
switch (msg.type) {
|
||||
case parser.yy.LINETYPE.NOTE:
|
||||
case diagObj.db.LINETYPE.NOTE:
|
||||
noteModel = msg.noteModel;
|
||||
drawNote(diagram, noteModel);
|
||||
break;
|
||||
case parser.yy.LINETYPE.ACTIVE_START:
|
||||
case diagObj.db.LINETYPE.ACTIVE_START:
|
||||
bounds.newActivation(msg, diagram, actors);
|
||||
break;
|
||||
case parser.yy.LINETYPE.ACTIVE_END:
|
||||
case diagObj.db.LINETYPE.ACTIVE_END:
|
||||
activeEnd(msg, bounds.getVerticalPos());
|
||||
break;
|
||||
case parser.yy.LINETYPE.LOOP_START:
|
||||
case diagObj.db.LINETYPE.LOOP_START:
|
||||
adjustLoopHeightForWrap(
|
||||
loopWidths,
|
||||
msg,
|
||||
@ -677,24 +677,24 @@ export const draw = function (text, id) {
|
||||
(message) => bounds.newLoop(message)
|
||||
);
|
||||
break;
|
||||
case parser.yy.LINETYPE.LOOP_END:
|
||||
case diagObj.db.LINETYPE.LOOP_END:
|
||||
loopModel = bounds.endLoop();
|
||||
svgDraw.drawLoop(diagram, loopModel, 'loop', conf);
|
||||
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
|
||||
bounds.models.addLoop(loopModel);
|
||||
break;
|
||||
case parser.yy.LINETYPE.RECT_START:
|
||||
case diagObj.db.LINETYPE.RECT_START:
|
||||
adjustLoopHeightForWrap(loopWidths, msg, conf.boxMargin, conf.boxMargin, (message) =>
|
||||
bounds.newLoop(undefined, message.message)
|
||||
);
|
||||
break;
|
||||
case parser.yy.LINETYPE.RECT_END:
|
||||
case diagObj.db.LINETYPE.RECT_END:
|
||||
loopModel = bounds.endLoop();
|
||||
svgDraw.drawBackgroundRect(diagram, loopModel);
|
||||
bounds.models.addLoop(loopModel);
|
||||
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
|
||||
break;
|
||||
case parser.yy.LINETYPE.OPT_START:
|
||||
case diagObj.db.LINETYPE.OPT_START:
|
||||
adjustLoopHeightForWrap(
|
||||
loopWidths,
|
||||
msg,
|
||||
@ -703,13 +703,13 @@ export const draw = function (text, id) {
|
||||
(message) => bounds.newLoop(message)
|
||||
);
|
||||
break;
|
||||
case parser.yy.LINETYPE.OPT_END:
|
||||
case diagObj.db.LINETYPE.OPT_END:
|
||||
loopModel = bounds.endLoop();
|
||||
svgDraw.drawLoop(diagram, loopModel, 'opt', conf);
|
||||
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
|
||||
bounds.models.addLoop(loopModel);
|
||||
break;
|
||||
case parser.yy.LINETYPE.ALT_START:
|
||||
case diagObj.db.LINETYPE.ALT_START:
|
||||
adjustLoopHeightForWrap(
|
||||
loopWidths,
|
||||
msg,
|
||||
@ -718,7 +718,7 @@ export const draw = function (text, id) {
|
||||
(message) => bounds.newLoop(message)
|
||||
);
|
||||
break;
|
||||
case parser.yy.LINETYPE.ALT_ELSE:
|
||||
case diagObj.db.LINETYPE.ALT_ELSE:
|
||||
adjustLoopHeightForWrap(
|
||||
loopWidths,
|
||||
msg,
|
||||
@ -727,13 +727,13 @@ export const draw = function (text, id) {
|
||||
(message) => bounds.addSectionToLoop(message)
|
||||
);
|
||||
break;
|
||||
case parser.yy.LINETYPE.ALT_END:
|
||||
case diagObj.db.LINETYPE.ALT_END:
|
||||
loopModel = bounds.endLoop();
|
||||
svgDraw.drawLoop(diagram, loopModel, 'alt', conf);
|
||||
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
|
||||
bounds.models.addLoop(loopModel);
|
||||
break;
|
||||
case parser.yy.LINETYPE.PAR_START:
|
||||
case diagObj.db.LINETYPE.PAR_START:
|
||||
adjustLoopHeightForWrap(
|
||||
loopWidths,
|
||||
msg,
|
||||
@ -742,7 +742,7 @@ export const draw = function (text, id) {
|
||||
(message) => bounds.newLoop(message)
|
||||
);
|
||||
break;
|
||||
case parser.yy.LINETYPE.PAR_AND:
|
||||
case diagObj.db.LINETYPE.PAR_AND:
|
||||
adjustLoopHeightForWrap(
|
||||
loopWidths,
|
||||
msg,
|
||||
@ -751,19 +751,19 @@ export const draw = function (text, id) {
|
||||
(message) => bounds.addSectionToLoop(message)
|
||||
);
|
||||
break;
|
||||
case parser.yy.LINETYPE.PAR_END:
|
||||
case diagObj.db.LINETYPE.PAR_END:
|
||||
loopModel = bounds.endLoop();
|
||||
svgDraw.drawLoop(diagram, loopModel, 'par', conf);
|
||||
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
|
||||
bounds.models.addLoop(loopModel);
|
||||
break;
|
||||
case parser.yy.LINETYPE.AUTONUMBER:
|
||||
case diagObj.db.LINETYPE.AUTONUMBER:
|
||||
sequenceIndex = msg.message.start || sequenceIndex;
|
||||
sequenceIndexStep = msg.message.step || sequenceIndexStep;
|
||||
if (msg.message.visible) parser.yy.enableSequenceNumbers();
|
||||
else parser.yy.disableSequenceNumbers();
|
||||
if (msg.message.visible) diagObj.db.enableSequenceNumbers();
|
||||
else diagObj.db.disableSequenceNumbers();
|
||||
break;
|
||||
case parser.yy.LINETYPE.CRITICAL_START:
|
||||
case diagObj.db.LINETYPE.CRITICAL_START:
|
||||
adjustLoopHeightForWrap(
|
||||
loopWidths,
|
||||
msg,
|
||||
@ -772,7 +772,7 @@ export const draw = function (text, id) {
|
||||
(message) => bounds.newLoop(message)
|
||||
);
|
||||
break;
|
||||
case parser.yy.LINETYPE.CRITICAL_OPTION:
|
||||
case diagObj.db.LINETYPE.CRITICAL_OPTION:
|
||||
adjustLoopHeightForWrap(
|
||||
loopWidths,
|
||||
msg,
|
||||
@ -781,13 +781,13 @@ export const draw = function (text, id) {
|
||||
(message) => bounds.addSectionToLoop(message)
|
||||
);
|
||||
break;
|
||||
case parser.yy.LINETYPE.CRITICAL_END:
|
||||
case diagObj.db.LINETYPE.CRITICAL_END:
|
||||
loopModel = bounds.endLoop();
|
||||
svgDraw.drawLoop(diagram, loopModel, 'critical', conf);
|
||||
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
|
||||
bounds.models.addLoop(loopModel);
|
||||
break;
|
||||
case parser.yy.LINETYPE.BREAK_START:
|
||||
case diagObj.db.LINETYPE.BREAK_START:
|
||||
adjustLoopHeightForWrap(
|
||||
loopWidths,
|
||||
msg,
|
||||
@ -796,7 +796,7 @@ export const draw = function (text, id) {
|
||||
(message) => bounds.newLoop(message)
|
||||
);
|
||||
break;
|
||||
case parser.yy.LINETYPE.BREAK_END:
|
||||
case diagObj.db.LINETYPE.BREAK_END:
|
||||
loopModel = bounds.endLoop();
|
||||
svgDraw.drawLoop(diagram, loopModel, 'break', conf);
|
||||
bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
|
||||
@ -808,7 +808,7 @@ export const draw = function (text, id) {
|
||||
msgModel = msg.msgModel;
|
||||
msgModel.starty = bounds.getVerticalPos();
|
||||
msgModel.sequenceIndex = sequenceIndex;
|
||||
msgModel.sequenceVisible = parser.yy.showSequenceNumbers();
|
||||
msgModel.sequenceVisible = diagObj.db.showSequenceNumbers();
|
||||
let lineStarty = boundMessage(diagram, msgModel);
|
||||
messagesToDraw.push({ messageModel: msgModel, lineStarty: lineStarty });
|
||||
bounds.models.addMessage(msgModel);
|
||||
@ -820,21 +820,21 @@ export const draw = function (text, id) {
|
||||
// Increment sequence counter if msg.type is a line (and not another event like activation or note, etc)
|
||||
if (
|
||||
[
|
||||
parser.yy.LINETYPE.SOLID_OPEN,
|
||||
parser.yy.LINETYPE.DOTTED_OPEN,
|
||||
parser.yy.LINETYPE.SOLID,
|
||||
parser.yy.LINETYPE.DOTTED,
|
||||
parser.yy.LINETYPE.SOLID_CROSS,
|
||||
parser.yy.LINETYPE.DOTTED_CROSS,
|
||||
parser.yy.LINETYPE.SOLID_POINT,
|
||||
parser.yy.LINETYPE.DOTTED_POINT,
|
||||
diagObj.db.LINETYPE.SOLID_OPEN,
|
||||
diagObj.db.LINETYPE.DOTTED_OPEN,
|
||||
diagObj.db.LINETYPE.SOLID,
|
||||
diagObj.db.LINETYPE.DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_CROSS,
|
||||
diagObj.db.LINETYPE.DOTTED_CROSS,
|
||||
diagObj.db.LINETYPE.SOLID_POINT,
|
||||
diagObj.db.LINETYPE.DOTTED_POINT,
|
||||
].includes(msg.type)
|
||||
) {
|
||||
sequenceIndex = sequenceIndex + sequenceIndexStep;
|
||||
}
|
||||
});
|
||||
|
||||
messagesToDraw.forEach((e) => drawMessage(diagram, e.messageModel, e.lineStarty));
|
||||
messagesToDraw.forEach((e) => drawMessage(diagram, e.messageModel, e.lineStarty, diagObj));
|
||||
|
||||
if (conf.mirrorActors) {
|
||||
// Draw actors below diagram
|
||||
@ -895,7 +895,7 @@ export const draw = function (text, id) {
|
||||
(height + extraVertForTitle)
|
||||
);
|
||||
|
||||
addSVGAccessibilityFields(parser.yy, diagram, id);
|
||||
addSVGAccessibilityFields(diagObj.db, diagram, id);
|
||||
log.debug(`models:`, bounds.models);
|
||||
};
|
||||
|
||||
@ -907,9 +907,10 @@ export const draw = function (text, id) {
|
||||
*
|
||||
* @param {any} actors - The actors map
|
||||
* @param {Array} messages - A list of message objects to iterate
|
||||
* @param diagObj
|
||||
* @returns {any}
|
||||
*/
|
||||
const getMaxMessageWidthPerActor = function (actors, messages) {
|
||||
const getMaxMessageWidthPerActor = function (actors, messages, diagObj) {
|
||||
const maxMessageWidthPerActor = {};
|
||||
|
||||
messages.forEach(function (msg) {
|
||||
@ -917,12 +918,12 @@ const getMaxMessageWidthPerActor = function (actors, messages) {
|
||||
const actor = actors[msg.to];
|
||||
|
||||
// If this is the first actor, and the message is left of it, no need to calculate the margin
|
||||
if (msg.placement === parser.yy.PLACEMENT.LEFTOF && !actor.prevActor) {
|
||||
if (msg.placement === diagObj.db.PLACEMENT.LEFTOF && !actor.prevActor) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is the last actor, and the message is right of it, no need to calculate the margin
|
||||
if (msg.placement === parser.yy.PLACEMENT.RIGHTOF && !actor.nextActor) {
|
||||
if (msg.placement === diagObj.db.PLACEMENT.RIGHTOF && !actor.nextActor) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -972,17 +973,17 @@ const getMaxMessageWidthPerActor = function (actors, messages) {
|
||||
maxMessageWidthPerActor[msg.to] || 0,
|
||||
messageWidth / 2
|
||||
);
|
||||
} else if (msg.placement === parser.yy.PLACEMENT.RIGHTOF) {
|
||||
} else if (msg.placement === diagObj.db.PLACEMENT.RIGHTOF) {
|
||||
maxMessageWidthPerActor[msg.from] = Math.max(
|
||||
maxMessageWidthPerActor[msg.from] || 0,
|
||||
messageWidth
|
||||
);
|
||||
} else if (msg.placement === parser.yy.PLACEMENT.LEFTOF) {
|
||||
} else if (msg.placement === diagObj.db.PLACEMENT.LEFTOF) {
|
||||
maxMessageWidthPerActor[actor.prevActor] = Math.max(
|
||||
maxMessageWidthPerActor[actor.prevActor] || 0,
|
||||
messageWidth
|
||||
);
|
||||
} else if (msg.placement === parser.yy.PLACEMENT.OVER) {
|
||||
} else if (msg.placement === diagObj.db.PLACEMENT.OVER) {
|
||||
if (actor.prevActor) {
|
||||
maxMessageWidthPerActor[actor.prevActor] = Math.max(
|
||||
maxMessageWidthPerActor[actor.prevActor] || 0,
|
||||
@ -1070,7 +1071,7 @@ const calculateActorMargins = function (actors, actorToMessageWidth) {
|
||||
return Math.max(maxHeight, conf.height);
|
||||
};
|
||||
|
||||
const buildNoteModel = function (msg, actors) {
|
||||
const buildNoteModel = function (msg, actors, diagObj) {
|
||||
let startx = actors[msg.from].x;
|
||||
let stopx = actors[msg.to].x;
|
||||
let shouldWrap = msg.wrap && msg.message;
|
||||
@ -1090,7 +1091,7 @@ const buildNoteModel = function (msg, actors) {
|
||||
stopy: 0,
|
||||
message: msg.message,
|
||||
};
|
||||
if (msg.placement === parser.yy.PLACEMENT.RIGHTOF) {
|
||||
if (msg.placement === diagObj.db.PLACEMENT.RIGHTOF) {
|
||||
noteModel.width = shouldWrap
|
||||
? Math.max(conf.width, textDimensions.width)
|
||||
: Math.max(
|
||||
@ -1098,7 +1099,7 @@ const buildNoteModel = function (msg, actors) {
|
||||
textDimensions.width + 2 * conf.noteMargin
|
||||
);
|
||||
noteModel.startx = startx + (actors[msg.from].width + conf.actorMargin) / 2;
|
||||
} else if (msg.placement === parser.yy.PLACEMENT.LEFTOF) {
|
||||
} else if (msg.placement === diagObj.db.PLACEMENT.LEFTOF) {
|
||||
noteModel.width = shouldWrap
|
||||
? Math.max(conf.width, textDimensions.width + 2 * conf.noteMargin)
|
||||
: Math.max(
|
||||
@ -1139,18 +1140,18 @@ const buildNoteModel = function (msg, actors) {
|
||||
return noteModel;
|
||||
};
|
||||
|
||||
const buildMessageModel = function (msg, actors) {
|
||||
const buildMessageModel = function (msg, actors, diagObj) {
|
||||
let process = false;
|
||||
if (
|
||||
[
|
||||
parser.yy.LINETYPE.SOLID_OPEN,
|
||||
parser.yy.LINETYPE.DOTTED_OPEN,
|
||||
parser.yy.LINETYPE.SOLID,
|
||||
parser.yy.LINETYPE.DOTTED,
|
||||
parser.yy.LINETYPE.SOLID_CROSS,
|
||||
parser.yy.LINETYPE.DOTTED_CROSS,
|
||||
parser.yy.LINETYPE.SOLID_POINT,
|
||||
parser.yy.LINETYPE.DOTTED_POINT,
|
||||
diagObj.db.LINETYPE.SOLID_OPEN,
|
||||
diagObj.db.LINETYPE.DOTTED_OPEN,
|
||||
diagObj.db.LINETYPE.SOLID,
|
||||
diagObj.db.LINETYPE.DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_CROSS,
|
||||
diagObj.db.LINETYPE.DOTTED_CROSS,
|
||||
diagObj.db.LINETYPE.SOLID_POINT,
|
||||
diagObj.db.LINETYPE.DOTTED_POINT,
|
||||
].includes(msg.type)
|
||||
) {
|
||||
process = true;
|
||||
@ -1192,7 +1193,7 @@ const buildMessageModel = function (msg, actors) {
|
||||
};
|
||||
};
|
||||
|
||||
const calculateLoopBounds = function (messages, actors) {
|
||||
const calculateLoopBounds = function (messages, actors, _maxWidthPerActor, diagObj) {
|
||||
const loops = {};
|
||||
const stack = [];
|
||||
let current, noteModel, msgModel;
|
||||
@ -1200,12 +1201,12 @@ const calculateLoopBounds = function (messages, actors) {
|
||||
messages.forEach(function (msg) {
|
||||
msg.id = utils.random({ length: 10 });
|
||||
switch (msg.type) {
|
||||
case parser.yy.LINETYPE.LOOP_START:
|
||||
case parser.yy.LINETYPE.ALT_START:
|
||||
case parser.yy.LINETYPE.OPT_START:
|
||||
case parser.yy.LINETYPE.PAR_START:
|
||||
case parser.yy.LINETYPE.CRITICAL_START:
|
||||
case parser.yy.LINETYPE.BREAK_START:
|
||||
case diagObj.db.LINETYPE.LOOP_START:
|
||||
case diagObj.db.LINETYPE.ALT_START:
|
||||
case diagObj.db.LINETYPE.OPT_START:
|
||||
case diagObj.db.LINETYPE.PAR_START:
|
||||
case diagObj.db.LINETYPE.CRITICAL_START:
|
||||
case diagObj.db.LINETYPE.BREAK_START:
|
||||
stack.push({
|
||||
id: msg.id,
|
||||
msg: msg.message,
|
||||
@ -1214,9 +1215,9 @@ const calculateLoopBounds = function (messages, actors) {
|
||||
width: 0,
|
||||
});
|
||||
break;
|
||||
case parser.yy.LINETYPE.ALT_ELSE:
|
||||
case parser.yy.LINETYPE.PAR_AND:
|
||||
case parser.yy.LINETYPE.CRITICAL_OPTION:
|
||||
case diagObj.db.LINETYPE.ALT_ELSE:
|
||||
case diagObj.db.LINETYPE.PAR_AND:
|
||||
case diagObj.db.LINETYPE.CRITICAL_OPTION:
|
||||
if (msg.message) {
|
||||
current = stack.pop();
|
||||
loops[current.id] = current;
|
||||
@ -1224,16 +1225,16 @@ const calculateLoopBounds = function (messages, actors) {
|
||||
stack.push(current);
|
||||
}
|
||||
break;
|
||||
case parser.yy.LINETYPE.LOOP_END:
|
||||
case parser.yy.LINETYPE.ALT_END:
|
||||
case parser.yy.LINETYPE.OPT_END:
|
||||
case parser.yy.LINETYPE.PAR_END:
|
||||
case parser.yy.LINETYPE.CRITICAL_END:
|
||||
case parser.yy.LINETYPE.BREAK_END:
|
||||
case diagObj.db.LINETYPE.LOOP_END:
|
||||
case diagObj.db.LINETYPE.ALT_END:
|
||||
case diagObj.db.LINETYPE.OPT_END:
|
||||
case diagObj.db.LINETYPE.PAR_END:
|
||||
case diagObj.db.LINETYPE.CRITICAL_END:
|
||||
case diagObj.db.LINETYPE.BREAK_END:
|
||||
current = stack.pop();
|
||||
loops[current.id] = current;
|
||||
break;
|
||||
case parser.yy.LINETYPE.ACTIVE_START:
|
||||
case diagObj.db.LINETYPE.ACTIVE_START:
|
||||
{
|
||||
const actorRect = actors[msg.from ? msg.from.actor : msg.to.actor];
|
||||
const stackedSize = actorActivations(msg.from ? msg.from.actor : msg.to.actor).length;
|
||||
@ -1248,7 +1249,7 @@ const calculateLoopBounds = function (messages, actors) {
|
||||
bounds.activations.push(toAdd);
|
||||
}
|
||||
break;
|
||||
case parser.yy.LINETYPE.ACTIVE_END:
|
||||
case diagObj.db.LINETYPE.ACTIVE_END:
|
||||
{
|
||||
const lastActorActivationIdx = bounds.activations
|
||||
.map((a) => a.actor)
|
||||
@ -1259,7 +1260,7 @@ const calculateLoopBounds = function (messages, actors) {
|
||||
}
|
||||
const isNote = msg.placement !== undefined;
|
||||
if (isNote) {
|
||||
noteModel = buildNoteModel(msg, actors);
|
||||
noteModel = buildNoteModel(msg, actors, diagObj);
|
||||
msg.noteModel = noteModel;
|
||||
stack.forEach((stk) => {
|
||||
current = stk;
|
||||
@ -1269,7 +1270,7 @@ const calculateLoopBounds = function (messages, actors) {
|
||||
Math.max(current.width, Math.abs(current.from - current.to)) - conf.labelBoxWidth;
|
||||
});
|
||||
} else {
|
||||
msgModel = buildMessageModel(msg, actors);
|
||||
msgModel = buildMessageModel(msg, actors, diagObj);
|
||||
msg.msgModel = msgModel;
|
||||
if (msgModel.startx && msgModel.stopx && stack.length > 0) {
|
||||
stack.forEach((stk) => {
|
||||
|
@ -193,7 +193,7 @@ export const drawText = function (elem, textData) {
|
||||
case 'start':
|
||||
textData.x = Math.round(textData.x + textData.textMargin);
|
||||
textData.anchor = 'start';
|
||||
textData.dominantBaseline = 'text-after-edge';
|
||||
textData.dominantBaseline = 'middle';
|
||||
textData.alignmentBaseline = 'middle';
|
||||
break;
|
||||
case 'middle':
|
||||
@ -207,7 +207,7 @@ export const drawText = function (elem, textData) {
|
||||
case 'end':
|
||||
textData.x = Math.round(textData.x + textData.width - textData.textMargin);
|
||||
textData.anchor = 'end';
|
||||
textData.dominantBaseline = 'text-before-edge';
|
||||
textData.dominantBaseline = 'middle';
|
||||
textData.alignmentBaseline = 'middle';
|
||||
break;
|
||||
}
|
||||
@ -847,9 +847,12 @@ const _drawTextCandidateFunc = (function () {
|
||||
function byTspan(content, g, x, y, width, height, textAttrs, conf) {
|
||||
const { actorFontSize, actorFontFamily, actorFontWeight } = conf;
|
||||
|
||||
let _actorFontSize =
|
||||
actorFontSize && actorFontSize.replace ? actorFontSize.replace('px', '') : actorFontSize;
|
||||
|
||||
const lines = content.split(common.lineBreakRegex);
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const dy = i * actorFontSize - (actorFontSize * (lines.length - 1)) / 2;
|
||||
const dy = i * _actorFontSize - (_actorFontSize * (lines.length - 1)) / 2;
|
||||
const text = g
|
||||
.append('text')
|
||||
.attr('x', x + width / 2)
|
||||
|
@ -1,7 +1,5 @@
|
||||
import graphlib from 'graphlib';
|
||||
import { select } from 'd3';
|
||||
import stateDb from './stateDb';
|
||||
import state from './parser/stateDiagram';
|
||||
import { getConfig } from '../../config';
|
||||
import { render } from '../../dagre-wrapper/index.js';
|
||||
import { log } from '../../logger';
|
||||
@ -23,17 +21,16 @@ let nodeDb = {};
|
||||
* Returns the all the styles from classDef statements in the graph definition.
|
||||
*
|
||||
* @param {any} text
|
||||
* @param diag
|
||||
* @returns {object} ClassDef styles
|
||||
*/
|
||||
export const getClasses = function (text) {
|
||||
export const getClasses = function (text, diag) {
|
||||
log.trace('Extracting classes');
|
||||
stateDb.clear();
|
||||
const parser = state.parser;
|
||||
parser.yy = stateDb;
|
||||
diag.sb.clear();
|
||||
|
||||
// Parse the graph definition
|
||||
parser.parse(text);
|
||||
return stateDb.getClasses();
|
||||
diag.parser.parse(text);
|
||||
return diag.sb.getClasses();
|
||||
};
|
||||
|
||||
const setupNode = (g, parent, node, altFlag) => {
|
||||
@ -238,19 +235,15 @@ const getDir = (nodes, defaultDir) => {
|
||||
*
|
||||
* @param {any} text
|
||||
* @param {any} id
|
||||
* @param _version
|
||||
* @param diag
|
||||
*/
|
||||
export const draw = function (text, id) {
|
||||
export const draw = function (text, id, _version, diag) {
|
||||
log.info('Drawing state diagram (v2)', id);
|
||||
stateDb.clear();
|
||||
// diag.sb.clear();
|
||||
nodeDb = {};
|
||||
const parser = state.parser;
|
||||
parser.yy = stateDb;
|
||||
|
||||
// Parse the graph definition
|
||||
parser.parse(text);
|
||||
|
||||
// Fetch the default direction, use TD if none was found
|
||||
let dir = stateDb.getDirection();
|
||||
let dir = diag.db.getDirection();
|
||||
if (typeof dir === 'undefined') {
|
||||
dir = 'LR';
|
||||
}
|
||||
@ -261,9 +254,9 @@ export const draw = function (text, id) {
|
||||
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
|
||||
log.info(stateDb.getRootDocV2());
|
||||
stateDb.extract(stateDb.getRootDocV2());
|
||||
log.info(stateDb.getRootDocV2());
|
||||
log.info(diag.db.getRootDocV2());
|
||||
diag.db.extract(diag.db.getRootDocV2());
|
||||
log.info(diag.db.getRootDocV2());
|
||||
|
||||
// Create the input mermaid.graph
|
||||
const g = new graphlib.Graph({
|
||||
@ -271,7 +264,7 @@ export const draw = function (text, id) {
|
||||
compound: true,
|
||||
})
|
||||
.setGraph({
|
||||
rankdir: getDir(stateDb.getRootDocV2()),
|
||||
rankdir: getDir(diag.db.getRootDocV2()),
|
||||
nodesep: nodeSpacing,
|
||||
ranksep: rankSpacing,
|
||||
marginx: 8,
|
||||
@ -281,7 +274,7 @@ export const draw = function (text, id) {
|
||||
return {};
|
||||
});
|
||||
|
||||
setupNode(g, undefined, stateDb.getRootDocV2(), true);
|
||||
setupNode(g, undefined, diag.db.getRootDocV2(), true);
|
||||
|
||||
// Set up an SVG group so that we can translate the final graph.
|
||||
let sandboxElement;
|
||||
@ -337,7 +330,7 @@ export const draw = function (text, id) {
|
||||
label.insertBefore(rect, label.firstChild);
|
||||
// }
|
||||
}
|
||||
addSVGAccessibilityFields(parser.yy, svg, id);
|
||||
addSVGAccessibilityFields(diag.db, svg, id);
|
||||
};
|
||||
|
||||
export default {
|
||||
|
@ -2,17 +2,12 @@ import { select } from 'd3';
|
||||
import dagre from 'dagre';
|
||||
import graphlib from 'graphlib';
|
||||
import { log } from '../../logger';
|
||||
import stateDb from './stateDb';
|
||||
import common from '../common/common';
|
||||
import { parser } from './parser/stateDiagram';
|
||||
// import idCache from './id-cache';
|
||||
import { drawState, addTitleAndBox, drawEdge } from './shapes';
|
||||
import { getConfig } from '../../config';
|
||||
import { configureSvgSize } from '../../utils';
|
||||
import addSVGAccessibilityFields from '../../accessibility';
|
||||
|
||||
parser.yy = stateDb;
|
||||
|
||||
// TODO Move conf object to main conf in mermaidAPI
|
||||
let conf;
|
||||
|
||||
@ -44,8 +39,10 @@ const insertMarkers = function (elem) {
|
||||
*
|
||||
* @param {any} text
|
||||
* @param {any} id
|
||||
* @param _version
|
||||
* @param diagObj
|
||||
*/
|
||||
export const draw = function (text, id) {
|
||||
export const draw = function (text, id, _version, diagObj) {
|
||||
conf = getConfig().state;
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
// Handle root and Document for when rendering in sanbox mode
|
||||
@ -59,8 +56,8 @@ export const draw = function (text, id) {
|
||||
: select('body');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
parser.yy.clear();
|
||||
parser.parse(text);
|
||||
// diagObj.db.clear();
|
||||
// parser.parse(text);
|
||||
log.debug('Rendering diagram ' + text);
|
||||
|
||||
// Fetch the default direction, use TD if none was found
|
||||
@ -81,8 +78,8 @@ export const draw = function (text, id) {
|
||||
return {};
|
||||
});
|
||||
|
||||
const rootDoc = stateDb.getRootDoc();
|
||||
renderDoc(rootDoc, diagram, undefined, false, root, doc);
|
||||
const rootDoc = diagObj.db.getRootDoc();
|
||||
renderDoc(rootDoc, diagram, undefined, false, root, doc, diagObj);
|
||||
|
||||
const padding = conf.padding;
|
||||
const bounds = diagram.node().getBBox();
|
||||
@ -98,13 +95,13 @@ export const draw = function (text, id) {
|
||||
'viewBox',
|
||||
`${bounds.x - conf.padding} ${bounds.y - conf.padding} ` + width + ' ' + height
|
||||
);
|
||||
addSVGAccessibilityFields(parser.yy, diagram, id);
|
||||
addSVGAccessibilityFields(diagObj.db, diagram, id);
|
||||
};
|
||||
const getLabelWidth = (text) => {
|
||||
return text ? text.length * conf.fontSizeFactor : 1;
|
||||
};
|
||||
|
||||
const renderDoc = (doc, diagram, parentId, altBkg, root, domDocument) => {
|
||||
const renderDoc = (doc, diagram, parentId, altBkg, root, domDocument, diagObj) => {
|
||||
// Layout graph, Create a new directed graph
|
||||
const graph = new graphlib.Graph({
|
||||
compound: true,
|
||||
@ -155,9 +152,9 @@ const renderDoc = (doc, diagram, parentId, altBkg, root, domDocument) => {
|
||||
return {};
|
||||
});
|
||||
|
||||
stateDb.extract(doc);
|
||||
const states = stateDb.getStates();
|
||||
const relations = stateDb.getRelations();
|
||||
diagObj.db.extract(doc);
|
||||
const states = diagObj.db.getStates();
|
||||
const relations = diagObj.db.getRelations();
|
||||
|
||||
const keys = Object.keys(states);
|
||||
|
||||
@ -173,7 +170,7 @@ const renderDoc = (doc, diagram, parentId, altBkg, root, domDocument) => {
|
||||
let node;
|
||||
if (stateDef.doc) {
|
||||
let sub = diagram.append('g').attr('id', stateDef.id).attr('class', 'stateGroup');
|
||||
node = renderDoc(stateDef.doc, sub, stateDef.id, !altBkg, root, domDocument);
|
||||
node = renderDoc(stateDef.doc, sub, stateDef.id, !altBkg, root, domDocument, diagObj);
|
||||
|
||||
if (first) {
|
||||
// first = false;
|
||||
|
@ -1,13 +1,9 @@
|
||||
import { select } from 'd3';
|
||||
import { parser } from './parser/journey';
|
||||
import journeyDb from './journeyDb';
|
||||
import svgDraw from './svgDraw';
|
||||
import { getConfig } from '../../config';
|
||||
import { configureSvgSize } from '../../utils';
|
||||
import addSVGAccessibilityFields from '../../accessibility';
|
||||
|
||||
parser.yy = journeyDb;
|
||||
|
||||
export const setConf = function (cnf) {
|
||||
const keys = Object.keys(cnf);
|
||||
|
||||
@ -50,10 +46,10 @@ function drawActorLegend(diagram) {
|
||||
}
|
||||
const conf = getConfig().journey;
|
||||
const LEFT_MARGIN = getConfig().journey.leftMargin;
|
||||
export const draw = function (text, id) {
|
||||
export const draw = function (text, id, version, diagObj) {
|
||||
const conf = getConfig().journey;
|
||||
parser.yy.clear();
|
||||
parser.parse(text + '\n');
|
||||
diagObj.db.clear();
|
||||
diagObj.parser.parse(text + '\n');
|
||||
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
// Handle root and Document for when rendering in sanbox mode
|
||||
@ -65,18 +61,17 @@ export const draw = function (text, id) {
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
// const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
bounds.init();
|
||||
const diagram = root.select('#' + id);
|
||||
diagram.attr('xmlns:xlink', 'http://www.w3.org/1999/xlink');
|
||||
|
||||
svgDraw.initGraphics(diagram);
|
||||
|
||||
const tasks = parser.yy.getTasks();
|
||||
const title = parser.yy.getDiagramTitle();
|
||||
const tasks = diagObj.db.getTasks();
|
||||
const title = diagObj.db.getDiagramTitle();
|
||||
|
||||
const actorNames = parser.yy.getActors();
|
||||
const actorNames = diagObj.db.getActors();
|
||||
for (let member in actors) delete actors[member];
|
||||
let actorPos = 0;
|
||||
actorNames.forEach((actorName) => {
|
||||
@ -123,7 +118,7 @@ export const draw = function (text, id) {
|
||||
diagram.attr('preserveAspectRatio', 'xMinYMin meet');
|
||||
diagram.attr('height', height + extraVertForTitle + 25);
|
||||
|
||||
addSVGAccessibilityFields(parser.yy, diagram, id);
|
||||
addSVGAccessibilityFields(diagObj.db, diagram, id);
|
||||
};
|
||||
|
||||
export const bounds = {
|
||||
|
@ -209,7 +209,7 @@ const setParseErrorHandler = function (newParseErrorHandler) {
|
||||
const mermaid = {
|
||||
startOnLoad: true,
|
||||
htmlLabels: true,
|
||||
|
||||
diagrams: {},
|
||||
mermaidAPI,
|
||||
parse: mermaidAPI != undefined ? mermaidAPI.parse : null,
|
||||
render: mermaidAPI != undefined ? mermaidAPI.render : null,
|
||||
|
@ -2,6 +2,7 @@ import mermaid from './mermaid';
|
||||
import flowDb from './diagrams/flowchart/flowDb';
|
||||
import flowParser from './diagrams/flowchart/parser/flow';
|
||||
import flowRenderer from './diagrams/flowchart/flowRenderer';
|
||||
import Diagram from './Diagram';
|
||||
|
||||
const spyOn = jest.spyOn;
|
||||
|
||||
@ -46,9 +47,9 @@ describe('when using mermaid and ', function () {
|
||||
flowDb.setGen('gen-2');
|
||||
});
|
||||
it('it should handle edges with text', function () {
|
||||
flowParser.parser.parse('graph TD;A-->|text ex|B;');
|
||||
flowParser.parser.yy.getVertices();
|
||||
const edges = flowParser.parser.yy.getEdges();
|
||||
const diag = new Diagram('graph TD;A-->|text ex|B;');
|
||||
diag.db.getVertices();
|
||||
const edges = diag.db.getEdges();
|
||||
|
||||
const mockG = {
|
||||
setEdge: function (start, end, options) {
|
||||
@ -59,13 +60,13 @@ describe('when using mermaid and ', function () {
|
||||
},
|
||||
};
|
||||
|
||||
flowRenderer.addEdges(edges, mockG);
|
||||
flowRenderer.addEdges(edges, mockG, diag);
|
||||
});
|
||||
|
||||
it('should handle edges without text', function () {
|
||||
flowParser.parser.parse('graph TD;A-->B;');
|
||||
flowParser.parser.yy.getVertices();
|
||||
const edges = flowParser.parser.yy.getEdges();
|
||||
const diag = new Diagram('graph TD;A-->B;');
|
||||
diag.db.getVertices();
|
||||
const edges = diag.db.getEdges();
|
||||
|
||||
const mockG = {
|
||||
setEdge: function (start, end, options) {
|
||||
@ -75,13 +76,13 @@ describe('when using mermaid and ', function () {
|
||||
},
|
||||
};
|
||||
|
||||
flowRenderer.addEdges(edges, mockG);
|
||||
flowRenderer.addEdges(edges, mockG, diag);
|
||||
});
|
||||
|
||||
it('should handle open-ended edges', function () {
|
||||
flowParser.parser.parse('graph TD;A---B;');
|
||||
flowParser.parser.yy.getVertices();
|
||||
const edges = flowParser.parser.yy.getEdges();
|
||||
const diag = new Diagram('graph TD;A---B;');
|
||||
diag.db.getVertices();
|
||||
const edges = diag.db.getEdges();
|
||||
|
||||
const mockG = {
|
||||
setEdge: function (start, end, options) {
|
||||
@ -91,13 +92,13 @@ describe('when using mermaid and ', function () {
|
||||
},
|
||||
};
|
||||
|
||||
flowRenderer.addEdges(edges, mockG);
|
||||
flowRenderer.addEdges(edges, mockG, diag);
|
||||
});
|
||||
|
||||
it('should handle edges with styles defined', function () {
|
||||
flowParser.parser.parse('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;');
|
||||
flowParser.parser.yy.getVertices();
|
||||
const edges = flowParser.parser.yy.getEdges();
|
||||
const diag = new Diagram('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;');
|
||||
diag.db.getVertices();
|
||||
const edges = diag.db.getEdges();
|
||||
|
||||
const mockG = {
|
||||
setEdge: function (start, end, options) {
|
||||
@ -108,12 +109,12 @@ describe('when using mermaid and ', function () {
|
||||
},
|
||||
};
|
||||
|
||||
flowRenderer.addEdges(edges, mockG);
|
||||
flowRenderer.addEdges(edges, mockG, diag);
|
||||
});
|
||||
it('should handle edges with interpolation defined', function () {
|
||||
flowParser.parser.parse('graph TD;A---B; linkStyle 0 interpolate basis');
|
||||
flowParser.parser.yy.getVertices();
|
||||
const edges = flowParser.parser.yy.getEdges();
|
||||
const diag = new Diagram('graph TD;A---B; linkStyle 0 interpolate basis');
|
||||
diag.db.getVertices();
|
||||
const edges = diag.db.getEdges();
|
||||
|
||||
const mockG = {
|
||||
setEdge: function (start, end, options) {
|
||||
@ -124,14 +125,14 @@ describe('when using mermaid and ', function () {
|
||||
},
|
||||
};
|
||||
|
||||
flowRenderer.addEdges(edges, mockG);
|
||||
flowRenderer.addEdges(edges, mockG, diag);
|
||||
});
|
||||
it('should handle edges with text and styles defined', function () {
|
||||
flowParser.parser.parse(
|
||||
const diag = new Diagram(
|
||||
'graph TD;A---|the text|B; linkStyle 0 stroke:val1,stroke-width:val2;'
|
||||
);
|
||||
flowParser.parser.yy.getVertices();
|
||||
const edges = flowParser.parser.yy.getEdges();
|
||||
diag.db.getVertices();
|
||||
const edges = diag.db.getEdges();
|
||||
|
||||
const mockG = {
|
||||
setEdge: function (start, end, options) {
|
||||
@ -143,13 +144,13 @@ describe('when using mermaid and ', function () {
|
||||
},
|
||||
};
|
||||
|
||||
flowRenderer.addEdges(edges, mockG);
|
||||
flowRenderer.addEdges(edges, mockG, diag);
|
||||
});
|
||||
|
||||
it('should set fill to "none" by default when handling edges', function () {
|
||||
flowParser.parser.parse('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;');
|
||||
flowParser.parser.yy.getVertices();
|
||||
const edges = flowParser.parser.yy.getEdges();
|
||||
const diag = new Diagram('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;');
|
||||
diag.db.getVertices();
|
||||
const edges = diag.db.getEdges();
|
||||
|
||||
const mockG = {
|
||||
setEdge: function (start, end, options) {
|
||||
@ -160,15 +161,15 @@ describe('when using mermaid and ', function () {
|
||||
},
|
||||
};
|
||||
|
||||
flowRenderer.addEdges(edges, mockG);
|
||||
flowRenderer.addEdges(edges, mockG, diag);
|
||||
});
|
||||
|
||||
it('should not set fill to none if fill is set in linkStyle', function () {
|
||||
flowParser.parser.parse(
|
||||
const diag = new Diagram(
|
||||
'graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2,fill:blue;'
|
||||
);
|
||||
flowParser.parser.yy.getVertices();
|
||||
const edges = flowParser.parser.yy.getEdges();
|
||||
diag.db.getVertices();
|
||||
const edges = diag.db.getEdges();
|
||||
const mockG = {
|
||||
setEdge: function (start, end, options) {
|
||||
expect(start).toContain('flowchart-A-');
|
||||
@ -178,7 +179,7 @@ describe('when using mermaid and ', function () {
|
||||
},
|
||||
};
|
||||
|
||||
flowRenderer.addEdges(edges, mockG);
|
||||
flowRenderer.addEdges(edges, mockG, diag);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -19,153 +19,38 @@ import { select } from 'd3';
|
||||
import { compile, serialize, stringify } from 'stylis';
|
||||
import pkg from '../package.json';
|
||||
import * as configApi from './config';
|
||||
import c4Db from './diagrams/c4/c4Db';
|
||||
import c4Renderer from './diagrams/c4/c4Renderer';
|
||||
import c4Parser from './diagrams/c4/parser/c4Diagram';
|
||||
import addDiagrams from './diagram-api/diagram-orchestration';
|
||||
import classDb from './diagrams/class/classDb';
|
||||
import classRenderer from './diagrams/class/classRenderer';
|
||||
import classRendererV2 from './diagrams/class/classRenderer-v2';
|
||||
import classParser from './diagrams/class/parser/classDiagram';
|
||||
import erDb from './diagrams/er/erDb';
|
||||
import erRenderer from './diagrams/er/erRenderer';
|
||||
import erParser from './diagrams/er/parser/erDiagram';
|
||||
import flowDb from './diagrams/flowchart/flowDb';
|
||||
import flowRenderer from './diagrams/flowchart/flowRenderer';
|
||||
import flowRendererV2 from './diagrams/flowchart/flowRenderer-v2';
|
||||
import flowParser from './diagrams/flowchart/parser/flow';
|
||||
import ganttDb from './diagrams/gantt/ganttDb';
|
||||
import ganttRenderer from './diagrams/gantt/ganttRenderer';
|
||||
import ganttParser from './diagrams/gantt/parser/gantt';
|
||||
import gitGraphAst from './diagrams/git/gitGraphAst';
|
||||
import gitGraphRenderer from './diagrams/git/gitGraphRenderer';
|
||||
import gitGraphParser from './diagrams/git/parser/gitGraph';
|
||||
import infoDb from './diagrams/info/infoDb';
|
||||
import infoRenderer from './diagrams/info/infoRenderer';
|
||||
import infoParser from './diagrams/info/parser/info';
|
||||
import pieParser from './diagrams/pie/parser/pie';
|
||||
import pieDb from './diagrams/pie/pieDb';
|
||||
import pieRenderer from './diagrams/pie/pieRenderer';
|
||||
import addSVGAccessibilityFields from './diagrams/pie/pieRenderer';
|
||||
import requirementParser from './diagrams/requirement/parser/requirementDiagram';
|
||||
import requirementDb from './diagrams/requirement/requirementDb';
|
||||
import requirementRenderer from './diagrams/requirement/requirementRenderer';
|
||||
import sequenceParser from './diagrams/sequence/parser/sequenceDiagram';
|
||||
import sequenceDb from './diagrams/sequence/sequenceDb';
|
||||
import sequenceRenderer from './diagrams/sequence/sequenceRenderer';
|
||||
import stateParser from './diagrams/state/parser/stateDiagram';
|
||||
import stateDb from './diagrams/state/stateDb';
|
||||
import stateRenderer from './diagrams/state/stateRenderer';
|
||||
import stateRendererV2 from './diagrams/state/stateRenderer-v2';
|
||||
import journeyDb from './diagrams/user-journey/journeyDb';
|
||||
import journeyRenderer from './diagrams/user-journey/journeyRenderer';
|
||||
import journeyParser from './diagrams/user-journey/parser/journey';
|
||||
import Diagram from './Diagram';
|
||||
import errorRenderer from './errorRenderer';
|
||||
import { attachFunctions } from './interactionDb';
|
||||
import { log, setLogLevel } from './logger';
|
||||
import getStyles from './styles';
|
||||
import theme from './themes';
|
||||
import utils, { directiveSanitizer, assignWithDepth, sanitizeCss } from './utils';
|
||||
import utils, { directiveSanitizer } from './utils';
|
||||
import assignWithDepth from './assignWithDepth';
|
||||
import DOMPurify from 'dompurify';
|
||||
import mermaid from './mermaid';
|
||||
|
||||
/**
|
||||
* @param text
|
||||
* @param dia
|
||||
* @returns {any}
|
||||
*/
|
||||
function parse(text) {
|
||||
function parse(text, dia) {
|
||||
var parseEncounteredException = false;
|
||||
try {
|
||||
text = text + '\n';
|
||||
const cnf = configApi.getConfig();
|
||||
const graphInit = utils.detectInit(text, cnf);
|
||||
if (graphInit) {
|
||||
reinitialize(graphInit);
|
||||
log.info('reinit ', graphInit);
|
||||
}
|
||||
const graphType = utils.detectType(text, cnf);
|
||||
let parser;
|
||||
|
||||
log.debug('Type ' + graphType);
|
||||
switch (graphType) {
|
||||
case 'c4':
|
||||
c4Db.clear();
|
||||
parser = c4Parser;
|
||||
parser.parser.yy = c4Db;
|
||||
break;
|
||||
case 'gitGraph':
|
||||
gitGraphAst.clear();
|
||||
parser = gitGraphParser;
|
||||
parser.parser.yy = gitGraphAst;
|
||||
break;
|
||||
case 'flowchart':
|
||||
flowDb.clear();
|
||||
parser = flowParser;
|
||||
parser.parser.yy = flowDb;
|
||||
break;
|
||||
case 'flowchart-v2':
|
||||
flowDb.clear();
|
||||
parser = flowParser;
|
||||
parser.parser.yy = flowDb;
|
||||
break;
|
||||
case 'sequence':
|
||||
sequenceDb.clear();
|
||||
parser = sequenceParser;
|
||||
parser.parser.yy = sequenceDb;
|
||||
break;
|
||||
case 'gantt':
|
||||
parser = ganttParser;
|
||||
parser.parser.yy = ganttDb;
|
||||
break;
|
||||
case 'class':
|
||||
parser = classParser;
|
||||
parser.parser.yy = classDb;
|
||||
break;
|
||||
case 'classDiagram':
|
||||
parser = classParser;
|
||||
parser.parser.yy = classDb;
|
||||
break;
|
||||
case 'state':
|
||||
parser = stateParser;
|
||||
parser.parser.yy = stateDb;
|
||||
break;
|
||||
case 'stateDiagram':
|
||||
parser = stateParser;
|
||||
parser.parser.yy = stateDb;
|
||||
break;
|
||||
case 'info':
|
||||
log.debug('info info info');
|
||||
parser = infoParser;
|
||||
parser.parser.yy = infoDb;
|
||||
break;
|
||||
case 'pie':
|
||||
log.debug('pie');
|
||||
parser = pieParser;
|
||||
parser.parser.yy = pieDb;
|
||||
break;
|
||||
case 'er':
|
||||
log.debug('er');
|
||||
parser = erParser;
|
||||
parser.parser.yy = erDb;
|
||||
break;
|
||||
case 'journey':
|
||||
log.debug('Journey');
|
||||
parser = journeyParser;
|
||||
parser.parser.yy = journeyDb;
|
||||
break;
|
||||
case 'requirement':
|
||||
case 'requirementDiagram':
|
||||
log.debug('RequirementDiagram');
|
||||
parser = requirementParser;
|
||||
parser.parser.yy = requirementDb;
|
||||
break;
|
||||
}
|
||||
parser.parser.yy.graphType = graphType;
|
||||
parser.parser.yy.parseError = (str, hash) => {
|
||||
const error = { str, hash };
|
||||
throw error;
|
||||
};
|
||||
|
||||
parser.parse(text);
|
||||
const diag = dia ? dia : new Diagram(text);
|
||||
diag.db.clear();
|
||||
return diag.parse(text);
|
||||
} catch (error) {
|
||||
parseEncounteredException = true;
|
||||
// Is this the correct way to access mermiad's parseError()
|
||||
@ -269,7 +154,6 @@ const render = function (id, _txt, cb, container) {
|
||||
txt = 'graph TB;a[Maximum text size in diagram exceeded];style a fill:#faa';
|
||||
}
|
||||
|
||||
// let d3Iframe;
|
||||
let root = select('body');
|
||||
|
||||
// In regular execution the container will be the div with a mermaid class
|
||||
@ -282,7 +166,6 @@ const render = function (id, _txt, cb, container) {
|
||||
.attr('id', 'i' + id)
|
||||
.attr('style', 'width: 100%; height: 100%;')
|
||||
.attr('sandbox', '');
|
||||
// const iframeBody = ;
|
||||
root = select(iframe.nodes()[0].contentDocument.body);
|
||||
root.node().style.margin = 0;
|
||||
}
|
||||
@ -313,6 +196,7 @@ const render = function (id, _txt, cb, container) {
|
||||
.attr('id', id)
|
||||
.attr('width', '100%')
|
||||
.attr('xmlns', 'http://www.w3.org/2000/svg')
|
||||
.attr('xmlns:xlink', 'http://www.w3.org/1999/xlink')
|
||||
.append('g');
|
||||
} else {
|
||||
// No container was provided
|
||||
@ -334,15 +218,6 @@ const render = function (id, _txt, cb, container) {
|
||||
element.remove();
|
||||
}
|
||||
|
||||
// if (cnf.securityLevel === 'sandbox') {
|
||||
// const iframe = select('body')
|
||||
// .append('iframe')
|
||||
// .attr('id', 'i' + id)
|
||||
// .attr('sandbox', '');
|
||||
// // const iframeBody = ;
|
||||
// root = select(iframe.nodes()[0].contentDocument.body);
|
||||
// }
|
||||
|
||||
// Add the tmp div used for rendering with the id `d${id}`
|
||||
// d+id it will contain a svg with the id "id"
|
||||
|
||||
@ -354,7 +229,7 @@ const render = function (id, _txt, cb, container) {
|
||||
.attr('id', 'i' + id)
|
||||
.attr('style', 'width: 100%; height: 100%;')
|
||||
.attr('sandbox', '');
|
||||
// const iframeBody = ;
|
||||
|
||||
root = select(iframe.nodes()[0].contentDocument.body);
|
||||
root.node().style.margin = 0;
|
||||
} else {
|
||||
@ -375,9 +250,11 @@ const render = function (id, _txt, cb, container) {
|
||||
|
||||
txt = encodeEntities(txt);
|
||||
|
||||
// Imortant that we do not create the diagram until after the directives have been included
|
||||
const diag = new Diagram(txt);
|
||||
// Get the tmp element containing the the svg
|
||||
const element = root.select('#d' + id).node();
|
||||
const graphType = utils.detectType(txt, cnf);
|
||||
const graphType = diag.type;
|
||||
|
||||
// insert inline style into svg
|
||||
const svg = element.firstChild;
|
||||
@ -401,7 +278,7 @@ const render = function (id, _txt, cb, container) {
|
||||
|
||||
// classDef
|
||||
if (graphType === 'flowchart' || graphType === 'flowchart-v2' || graphType === 'graph') {
|
||||
const classes = flowRenderer.getClasses(txt);
|
||||
const classes = flowRenderer.getClasses(txt, diag);
|
||||
const htmlLabels = cnf.htmlLabels || cnf.flowchart.htmlLabels;
|
||||
for (const className in classes) {
|
||||
if (htmlLabels) {
|
||||
@ -436,8 +313,6 @@ const render = function (id, _txt, cb, container) {
|
||||
}
|
||||
}
|
||||
|
||||
// log.warn(cnf.themeVariables);
|
||||
|
||||
const stylis = (selector, styles) => serialize(compile(`${selector}{${styles}}`), stringify);
|
||||
const rules = stylis(`#${id}`, getStyles(graphType, userStyles, cnf.themeVariables));
|
||||
|
||||
@ -445,102 +320,9 @@ const render = function (id, _txt, cb, container) {
|
||||
style1.innerHTML = `#${id} ` + rules;
|
||||
svg.insertBefore(style1, firstChild);
|
||||
|
||||
// Verify that the generated svgs are ok before removing this
|
||||
|
||||
// const style2 = document.createElement('style');
|
||||
// const cs = window.getComputedStyle(svg);
|
||||
// style2.innerHTML = `#d${id} * {
|
||||
// color: ${cs.color};
|
||||
// // font: ${cs.font};
|
||||
// // font-family: Arial;
|
||||
// // font-size: 24px;
|
||||
// }`;
|
||||
// svg.insertBefore(style2, firstChild);
|
||||
|
||||
try {
|
||||
switch (graphType) {
|
||||
case 'c4':
|
||||
c4Renderer.setConf(cnf.c4);
|
||||
c4Renderer.draw(txt, id);
|
||||
break;
|
||||
case 'gitGraph':
|
||||
// cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
//gitGraphRenderer.setConf(cnf.git);
|
||||
gitGraphRenderer.draw(txt, id, false);
|
||||
break;
|
||||
case 'flowchart':
|
||||
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
flowRenderer.setConf(cnf.flowchart);
|
||||
flowRenderer.draw(txt, id, false);
|
||||
break;
|
||||
case 'flowchart-v2':
|
||||
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
flowRendererV2.setConf(cnf.flowchart);
|
||||
flowRendererV2.draw(txt, id, false);
|
||||
break;
|
||||
case 'sequence':
|
||||
cnf.sequence.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
if (cnf.sequenceDiagram) {
|
||||
// backwards compatibility
|
||||
sequenceRenderer.setConf(Object.assign(cnf.sequence, cnf.sequenceDiagram));
|
||||
console.error(
|
||||
'`mermaid config.sequenceDiagram` has been renamed to `config.sequence`. Please update your mermaid config.'
|
||||
);
|
||||
} else {
|
||||
sequenceRenderer.setConf(cnf.sequence);
|
||||
}
|
||||
sequenceRenderer.draw(txt, id);
|
||||
break;
|
||||
case 'gantt':
|
||||
cnf.gantt.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
ganttRenderer.setConf(cnf.gantt);
|
||||
ganttRenderer.draw(txt, id);
|
||||
break;
|
||||
case 'class':
|
||||
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
classRenderer.setConf(cnf.class);
|
||||
classRenderer.draw(txt, id);
|
||||
break;
|
||||
case 'classDiagram':
|
||||
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
classRendererV2.setConf(cnf.class);
|
||||
classRendererV2.draw(txt, id);
|
||||
break;
|
||||
case 'state':
|
||||
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
stateRenderer.setConf(cnf.state);
|
||||
stateRenderer.draw(txt, id);
|
||||
break;
|
||||
case 'stateDiagram':
|
||||
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
stateRendererV2.setConf(cnf.state);
|
||||
stateRendererV2.draw(txt, id);
|
||||
break;
|
||||
case 'info':
|
||||
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
infoRenderer.setConf(cnf.class);
|
||||
infoRenderer.draw(txt, id, pkg.version);
|
||||
break;
|
||||
case 'pie':
|
||||
//cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
//pieRenderer.setConf(cnf.pie);
|
||||
pieRenderer.draw(txt, id, pkg.version);
|
||||
break;
|
||||
case 'er':
|
||||
erRenderer.setConf(cnf.er);
|
||||
erRenderer.draw(txt, id, pkg.version);
|
||||
break;
|
||||
case 'journey':
|
||||
journeyRenderer.setConf(cnf.journey);
|
||||
journeyRenderer.draw(txt, id, pkg.version);
|
||||
break;
|
||||
case 'requirement':
|
||||
requirementRenderer.setConf(cnf.requirement);
|
||||
requirementRenderer.draw(txt, id, pkg.version);
|
||||
break;
|
||||
}
|
||||
diag.renderer.draw(txt, id, pkg.version, diag);
|
||||
} catch (e) {
|
||||
// errorRenderer.setConf(cnf.class);
|
||||
errorRenderer.draw(id, pkg.version);
|
||||
throw e;
|
||||
}
|
||||
@ -571,7 +353,6 @@ const render = function (id, _txt, cb, container) {
|
||||
let width = '100%';
|
||||
let height = '100%';
|
||||
if (svgEl) {
|
||||
// width = svgEl.viewBox.baseVal.width + 'px';
|
||||
height = svgEl.viewBox.baseVal.height + 'px';
|
||||
}
|
||||
svgCode = `<iframe style="width:${width};height:${height};border:0;margin:0;" src="data:text/html;base64,${btoa(
|
||||
@ -665,7 +446,6 @@ const handleDirective = function (p, directive, type) {
|
||||
log.debug('sanitize in handleDirective', directive.args);
|
||||
directiveSanitizer(directive.args);
|
||||
log.debug('sanitize in handleDirective (done)', directive.args);
|
||||
reinitialize(directive.args);
|
||||
configApi.addDirective(directive.args);
|
||||
break;
|
||||
}
|
||||
@ -693,7 +473,6 @@ const handleDirective = function (p, directive, type) {
|
||||
function updateRendererConfigs(conf) {
|
||||
// Todo remove, all diagrams should get config on demand from the config object, no need for this
|
||||
|
||||
// gitGraphRenderer.setConf(conf.git); // Todo Remove all of these
|
||||
flowRenderer.setConf(conf.flowchart);
|
||||
flowRendererV2.setConf(conf.flowchart);
|
||||
if (typeof conf['sequenceDiagram'] !== 'undefined') {
|
||||
@ -701,37 +480,16 @@ function updateRendererConfigs(conf) {
|
||||
}
|
||||
sequenceRenderer.setConf(conf.sequence);
|
||||
ganttRenderer.setConf(conf.gantt);
|
||||
classRenderer.setConf(conf.class);
|
||||
// classRenderer.setConf(conf.class);
|
||||
stateRenderer.setConf(conf.state);
|
||||
stateRendererV2.setConf(conf.state);
|
||||
infoRenderer.setConf(conf.class);
|
||||
// pieRenderer.setConf(conf.class);
|
||||
erRenderer.setConf(conf.er);
|
||||
// infoRenderer.setConf(conf.class);
|
||||
journeyRenderer.setConf(conf.journey);
|
||||
requirementRenderer.setConf(conf.requirement);
|
||||
errorRenderer.setConf(conf.class);
|
||||
}
|
||||
|
||||
/** To be removed */
|
||||
function reinitialize() {
|
||||
// `mermaidAPI.reinitialize: v${pkg.version}`,
|
||||
// JSON.stringify(options),
|
||||
// options.themeVariables.primaryColor;
|
||||
// // if (options.theme && theme[options.theme]) {
|
||||
// // options.themeVariables = theme[options.theme].getThemeVariables(options.themeVariables);
|
||||
// // }
|
||||
// // Set default options
|
||||
// const config =
|
||||
// typeof options === 'object' ? configApi.setConfig(options) : configApi.getSiteConfig();
|
||||
// updateRendererConfigs(config);
|
||||
// setLogLevel(config.logLevel);
|
||||
// log.debug('mermaidAPI.reinitialize: ', config);
|
||||
}
|
||||
|
||||
/** @param {any} options */
|
||||
function initialize(options) {
|
||||
// console.warn(`mermaidAPI.initialize: v${pkg.version} `, options);
|
||||
|
||||
// Handle legacy location of font-family configuration
|
||||
if (options && options.fontFamily) {
|
||||
if (!options.themeVariables) {
|
||||
@ -757,7 +515,7 @@ function initialize(options) {
|
||||
|
||||
updateRendererConfigs(config);
|
||||
setLogLevel(config.logLevel);
|
||||
// log.debug('mermaidAPI.initialize: ', config);
|
||||
addDiagrams();
|
||||
}
|
||||
|
||||
const mermaidAPI = Object.freeze({
|
||||
@ -765,16 +523,12 @@ const mermaidAPI = Object.freeze({
|
||||
parse,
|
||||
parseDirective,
|
||||
initialize,
|
||||
reinitialize,
|
||||
getConfig: configApi.getConfig,
|
||||
setConfig: configApi.setConfig,
|
||||
getSiteConfig: configApi.getSiteConfig,
|
||||
updateSiteConfig: configApi.updateSiteConfig,
|
||||
reset: () => {
|
||||
// console.warn('reset');
|
||||
configApi.reset();
|
||||
// const siteConfig = configApi.getSiteConfig();
|
||||
// updateRendererConfigs(siteConfig);
|
||||
},
|
||||
globalReset: () => {
|
||||
configApi.reset(configApi.defaultConfig);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import mermaid from './mermaid';
|
||||
import mermaidAPI from './mermaidAPI';
|
||||
import { assignWithDepth } from './utils';
|
||||
import assignWithDepth from './assignWithDepth';
|
||||
|
||||
describe('when using mermaidAPI and ', function () {
|
||||
describe('doing initialize ', function () {
|
||||
@ -64,7 +64,7 @@ describe('when using mermaidAPI and ', function () {
|
||||
mermaidAPI.initialize({ securityLevel: 'loose' });
|
||||
},
|
||||
};
|
||||
mermaidAPI.reinitialize(config);
|
||||
// mermaidAPI.reinitialize(config);
|
||||
expect(mermaidAPI.getConfig().secure).toEqual(mermaidAPI.getSiteConfig().secure);
|
||||
expect(mermaidAPI.getConfig().securityLevel).toBe('strict');
|
||||
mermaidAPI.reset();
|
||||
|
160
src/utils.js
160
src/utils.js
@ -16,6 +16,8 @@ import {
|
||||
import common from './diagrams/common/common';
|
||||
import { configKeys } from './defaultConfig';
|
||||
import { log } from './logger';
|
||||
import detectType from './diagram-api/detectType';
|
||||
import assignWithDepth from './assignWithDepth';
|
||||
|
||||
// Effectively an enum of the supported curve types, accessible by name
|
||||
const d3CurveTypes = {
|
||||
@ -160,90 +162,6 @@ export const detectDirective = function (text, type = null) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @function detectType Detects the type of the graph text. Takes into consideration the possible
|
||||
* existence of an %%init directive
|
||||
*
|
||||
* ```mermaid
|
||||
* %%{initialize: {"startOnLoad": true, logLevel: "fatal" }}%%
|
||||
* graph LR
|
||||
* a-->b
|
||||
* b-->c
|
||||
* c-->d
|
||||
* d-->e
|
||||
* e-->f
|
||||
* f-->g
|
||||
* g-->h
|
||||
* ```
|
||||
* @param {string} text The text defining the graph
|
||||
* @param {{
|
||||
* class: { defaultRenderer: string } | undefined;
|
||||
* state: { defaultRenderer: string } | undefined;
|
||||
* flowchart: { defaultRenderer: string } | undefined;
|
||||
* }} [cnf]
|
||||
* @returns {string} A graph definition key
|
||||
*/
|
||||
export const detectType = function (text, cnf) {
|
||||
text = text.replace(directive, '').replace(anyComment, '\n');
|
||||
if (text.match(/^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/)) {
|
||||
return 'c4';
|
||||
}
|
||||
|
||||
if (text.match(/^\s*sequenceDiagram/)) {
|
||||
return 'sequence';
|
||||
}
|
||||
|
||||
if (text.match(/^\s*gantt/)) {
|
||||
return 'gantt';
|
||||
}
|
||||
if (text.match(/^\s*classDiagram-v2/)) {
|
||||
return 'classDiagram';
|
||||
}
|
||||
if (text.match(/^\s*classDiagram/)) {
|
||||
if (cnf && cnf.class && cnf.class.defaultRenderer === 'dagre-wrapper') return 'classDiagram';
|
||||
return 'class';
|
||||
}
|
||||
|
||||
if (text.match(/^\s*stateDiagram-v2/)) {
|
||||
return 'stateDiagram';
|
||||
}
|
||||
|
||||
if (text.match(/^\s*stateDiagram/)) {
|
||||
if (cnf && cnf.class && cnf.state.defaultRenderer === 'dagre-wrapper') return 'stateDiagram';
|
||||
return 'state';
|
||||
}
|
||||
|
||||
if (text.match(/^\s*gitGraph/)) {
|
||||
return 'gitGraph';
|
||||
}
|
||||
if (text.match(/^\s*flowchart/)) {
|
||||
return 'flowchart-v2';
|
||||
}
|
||||
|
||||
if (text.match(/^\s*info/)) {
|
||||
return 'info';
|
||||
}
|
||||
if (text.match(/^\s*pie/)) {
|
||||
return 'pie';
|
||||
}
|
||||
|
||||
if (text.match(/^\s*erDiagram/)) {
|
||||
return 'er';
|
||||
}
|
||||
|
||||
if (text.match(/^\s*journey/)) {
|
||||
return 'journey';
|
||||
}
|
||||
|
||||
if (text.match(/^\s*requirement/) || text.match(/^\s*requirementDiagram/)) {
|
||||
return 'requirement';
|
||||
}
|
||||
if (cnf && cnf.flowchart && cnf.flowchart.defaultRenderer === 'dagre-wrapper')
|
||||
return 'flowchart-v2';
|
||||
|
||||
return 'flowchart';
|
||||
};
|
||||
|
||||
/**
|
||||
* Caches results of functions based on input
|
||||
*
|
||||
@ -578,79 +496,6 @@ export const random = (options) => {
|
||||
return makeid(options.length);
|
||||
};
|
||||
|
||||
/**
|
||||
* @function assignWithDepth Extends the functionality of {@link ObjectConstructor.assign} with the
|
||||
* ability to merge arbitrary-depth objects For each key in src with path `k` (recursively)
|
||||
* performs an Object.assign(dst[`k`], src[`k`]) with a slight change from the typical handling of
|
||||
* undefined for dst[`k`]: instead of raising an error, dst[`k`] is auto-initialized to {} and
|
||||
* effectively merged with src[`k`]<p> Additionally, dissimilar types will not clobber unless the
|
||||
* config.clobber parameter === true. Example:
|
||||
*
|
||||
* ```js
|
||||
* let config_0 = { foo: { bar: 'bar' }, bar: 'foo' };
|
||||
* let config_1 = { foo: 'foo', bar: 'bar' };
|
||||
* let result = assignWithDepth(config_0, config_1);
|
||||
* console.log(result);
|
||||
* //-> result: { foo: { bar: 'bar' }, bar: 'bar' }
|
||||
* ```
|
||||
*
|
||||
* Traditional Object.assign would have clobbered foo in config_0 with foo in config_1. If src is a
|
||||
* destructured array of objects and dst is not an array, assignWithDepth will apply each element
|
||||
* of src to dst in order.
|
||||
* @param dst
|
||||
* @param src
|
||||
* @param config
|
||||
* @param dst
|
||||
* @param src
|
||||
* @param config
|
||||
* @param dst
|
||||
* @param src
|
||||
* @param config
|
||||
* @param {any} dst - The destination of the merge
|
||||
* @param {any} src - The source object(s) to merge into destination
|
||||
* @param {{ depth: number; clobber: boolean }} [config={ depth: 2, clobber: false }] - Depth: depth
|
||||
* to traverse within src and dst for merging - clobber: should dissimilar types clobber (default:
|
||||
* { depth: 2, clobber: false }). Default is `{ depth: 2, clobber: false }`
|
||||
* @returns {any}
|
||||
*/
|
||||
export const assignWithDepth = function (dst, src, config) {
|
||||
const { depth, clobber } = Object.assign({ depth: 2, clobber: false }, config);
|
||||
if (Array.isArray(src) && !Array.isArray(dst)) {
|
||||
src.forEach((s) => assignWithDepth(dst, s, config));
|
||||
return dst;
|
||||
} else if (Array.isArray(src) && Array.isArray(dst)) {
|
||||
src.forEach((s) => {
|
||||
if (dst.indexOf(s) === -1) {
|
||||
dst.push(s);
|
||||
}
|
||||
});
|
||||
return dst;
|
||||
}
|
||||
if (typeof dst === 'undefined' || depth <= 0) {
|
||||
if (dst !== undefined && dst !== null && typeof dst === 'object' && typeof src === 'object') {
|
||||
return Object.assign(dst, src);
|
||||
} else {
|
||||
return src;
|
||||
}
|
||||
}
|
||||
if (typeof src !== 'undefined' && typeof dst === 'object' && typeof src === 'object') {
|
||||
Object.keys(src).forEach((key) => {
|
||||
if (
|
||||
typeof src[key] === 'object' &&
|
||||
(dst[key] === undefined || typeof dst[key] === 'object')
|
||||
) {
|
||||
if (dst[key] === undefined) {
|
||||
dst[key] = Array.isArray(src[key]) ? [] : {};
|
||||
}
|
||||
dst[key] = assignWithDepth(dst[key], src[key], { depth: depth - 1, clobber });
|
||||
} else if (clobber || (typeof dst[key] !== 'object' && typeof src[key] !== 'object')) {
|
||||
dst[key] = src[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
return dst;
|
||||
};
|
||||
|
||||
export const getTextObj = function () {
|
||||
return {
|
||||
x: 0,
|
||||
@ -1096,7 +941,6 @@ export default {
|
||||
setupGraphViewbox,
|
||||
detectInit,
|
||||
detectDirective,
|
||||
detectType,
|
||||
isSubstringInArray,
|
||||
interpolateToCurve,
|
||||
calcLabelPosition,
|
||||
|
@ -1,52 +1,57 @@
|
||||
import utils from './utils';
|
||||
import assignWithDepth from './assignWithDepth';
|
||||
import detectType from './diagram-api/detectType';
|
||||
import addDiagrams from './diagram-api/diagram-orchestration';
|
||||
|
||||
addDiagrams();
|
||||
|
||||
describe('when assignWithDepth: should merge objects within objects', function () {
|
||||
it('should handle simple, depth:1 types (identity)', function () {
|
||||
let config_0 = { foo: 'bar', bar: 0 };
|
||||
let config_1 = { foo: 'bar', bar: 0 };
|
||||
let result = utils.assignWithDepth(config_0, config_1);
|
||||
let result = assignWithDepth(config_0, config_1);
|
||||
expect(result).toEqual(config_1);
|
||||
});
|
||||
it('should handle simple, depth:1 types (dst: undefined)', function () {
|
||||
let config_0 = undefined;
|
||||
let config_1 = { foo: 'bar', bar: 0 };
|
||||
let result = utils.assignWithDepth(config_0, config_1);
|
||||
let result = assignWithDepth(config_0, config_1);
|
||||
expect(result).toEqual(config_1);
|
||||
});
|
||||
it('should handle simple, depth:1 types (src: undefined)', function () {
|
||||
let config_0 = { foo: 'bar', bar: 0 };
|
||||
let config_1 = undefined;
|
||||
let result = utils.assignWithDepth(config_0, config_1);
|
||||
let result = assignWithDepth(config_0, config_1);
|
||||
expect(result).toEqual(config_0);
|
||||
});
|
||||
it('should handle simple, depth:1 types (merge)', function () {
|
||||
let config_0 = { foo: 'bar', bar: 0 };
|
||||
let config_1 = { foo: 'foo' };
|
||||
let result = utils.assignWithDepth(config_0, config_1);
|
||||
let result = assignWithDepth(config_0, config_1);
|
||||
expect(result).toEqual({ foo: 'foo', bar: 0 });
|
||||
});
|
||||
it('should handle depth:2 types (dst: orphan)', function () {
|
||||
let config_0 = { foo: 'bar', bar: { foo: 'bar' } };
|
||||
let config_1 = { foo: 'bar' };
|
||||
let result = utils.assignWithDepth(config_0, config_1);
|
||||
let result = assignWithDepth(config_0, config_1);
|
||||
expect(result).toEqual(config_0);
|
||||
});
|
||||
it('should handle depth:2 types (dst: object, src: simple type)', function () {
|
||||
let config_0 = { foo: 'bar', bar: { foo: 'bar' } };
|
||||
let config_1 = { foo: 'foo', bar: 'should NOT clobber' };
|
||||
let result = utils.assignWithDepth(config_0, config_1);
|
||||
let result = assignWithDepth(config_0, config_1);
|
||||
expect(result).toEqual({ foo: 'foo', bar: { foo: 'bar' } });
|
||||
});
|
||||
it('should handle depth:2 types (src: orphan)', function () {
|
||||
let config_0 = { foo: 'bar' };
|
||||
let config_1 = { foo: 'bar', bar: { foo: 'bar' } };
|
||||
let result = utils.assignWithDepth(config_0, config_1);
|
||||
let result = assignWithDepth(config_0, config_1);
|
||||
expect(result).toEqual(config_1);
|
||||
});
|
||||
it('should handle depth:2 types (merge)', function () {
|
||||
let config_0 = { foo: 'bar', bar: { foo: 'bar' }, boofar: 1 };
|
||||
let config_1 = { foo: 'foo', bar: { bar: 0 }, foobar: 'foobar' };
|
||||
let result = utils.assignWithDepth(config_0, config_1);
|
||||
let result = assignWithDepth(config_0, config_1);
|
||||
expect(result).toEqual({
|
||||
foo: 'foo',
|
||||
bar: { foo: 'bar', bar: 0 },
|
||||
@ -65,7 +70,7 @@ describe('when assignWithDepth: should merge objects within objects', function (
|
||||
bar: { foo: 'foo', bar: { foo: { message: 'clobbered other foo' } } },
|
||||
foobar: 'foobar',
|
||||
};
|
||||
let result = utils.assignWithDepth(config_0, config_1);
|
||||
let result = assignWithDepth(config_0, config_1);
|
||||
expect(result).toEqual({
|
||||
foo: 'foo',
|
||||
bar: { foo: 'foo', bar: { foo: { message: 'clobbered other foo' } } },
|
||||
@ -87,7 +92,7 @@ describe('when assignWithDepth: should merge objects within objects', function (
|
||||
bar: { foo: 'foo', bar: { foo: { message: 'this' } } },
|
||||
foobar: 'foobar',
|
||||
};
|
||||
let result = utils.assignWithDepth(config_0, config_1, { depth: 1 });
|
||||
let result = assignWithDepth(config_0, config_1, { depth: 1 });
|
||||
expect(result).toEqual({
|
||||
foo: 'foo',
|
||||
bar: { foo: 'foo', bar: { foo: { message: 'this' } } },
|
||||
@ -106,7 +111,7 @@ describe('when assignWithDepth: should merge objects within objects', function (
|
||||
bar: { foo: 'foo', bar: { foo: { message: 'this' } } },
|
||||
foobar: 'foobar',
|
||||
};
|
||||
let result = utils.assignWithDepth(config_0, config_1, { depth: 3 });
|
||||
let result = assignWithDepth(config_0, config_1, { depth: 3 });
|
||||
expect(result).toEqual({
|
||||
foo: 'foo',
|
||||
bar: { foo: 'foo', bar: { foo: { message: 'this', willbe: 'present' } } },
|
||||
@ -137,7 +142,7 @@ describe('when memoizing', function () {
|
||||
describe('when detecting chart type ', function () {
|
||||
it('should handle a graph definition', function () {
|
||||
const str = 'graph TB\nbfs1:queue';
|
||||
const type = utils.detectType(str);
|
||||
const type = detectType(str);
|
||||
expect(type).toBe('flowchart');
|
||||
});
|
||||
it('should handle an initialize definition', function () {
|
||||
@ -145,7 +150,7 @@ describe('when detecting chart type ', function () {
|
||||
%%{initialize: { 'logLevel': 0, 'theme': 'dark' }}%%
|
||||
sequenceDiagram
|
||||
Alice->Bob: hi`;
|
||||
const type = utils.detectType(str);
|
||||
const type = detectType(str);
|
||||
const init = utils.detectInit(str);
|
||||
expect(type).toBe('sequence');
|
||||
expect(init).toEqual({ logLevel: 0, theme: 'dark' });
|
||||
@ -155,7 +160,7 @@ Alice->Bob: hi`;
|
||||
%%{init: { 'logLevel': 0, 'theme': 'dark' }}%%
|
||||
sequenceDiagram
|
||||
Alice->Bob: hi`;
|
||||
const type = utils.detectType(str);
|
||||
const type = detectType(str);
|
||||
const init = utils.detectInit(str);
|
||||
expect(type).toBe('sequence');
|
||||
expect(init).toEqual({ logLevel: 0, theme: 'dark' });
|
||||
@ -165,7 +170,7 @@ Alice->Bob: hi`;
|
||||
%%{init: { 'logLevel': 0, 'theme': 'dark', 'config': {'wrap': true} } }%%
|
||||
sequenceDiagram
|
||||
Alice->Bob: hi`;
|
||||
const type = utils.detectType(str);
|
||||
const type = detectType(str);
|
||||
const init = utils.detectInit(str);
|
||||
expect(type).toBe('sequence');
|
||||
expect(init).toEqual({ logLevel: 0, theme: 'dark', sequence: { wrap: true } });
|
||||
@ -180,7 +185,7 @@ Alice->Bob: hi`;
|
||||
}%%
|
||||
sequenceDiagram
|
||||
Alice->Bob: hi`;
|
||||
const type = utils.detectType(str);
|
||||
const type = detectType(str);
|
||||
const init = utils.detectInit(str);
|
||||
expect(type).toBe('sequence');
|
||||
expect(init).toEqual({ logLevel: 0, theme: 'dark' });
|
||||
@ -195,25 +200,25 @@ Alice->Bob: hi`;
|
||||
}%%
|
||||
sequenceDiagram
|
||||
Alice->Bob: hi`;
|
||||
const type = utils.detectType(str);
|
||||
const type = detectType(str);
|
||||
const init = utils.detectInit(str);
|
||||
expect(type).toBe('sequence');
|
||||
expect(init).toEqual({ logLevel: 0, theme: 'dark' });
|
||||
});
|
||||
it('should handle a graph definition with leading spaces', function () {
|
||||
const str = ' graph TB\nbfs1:queue';
|
||||
const type = utils.detectType(str);
|
||||
const type = detectType(str);
|
||||
expect(type).toBe('flowchart');
|
||||
});
|
||||
|
||||
it('should handle a graph definition with leading spaces and newline', function () {
|
||||
const str = ' \n graph TB\nbfs1:queue';
|
||||
const type = utils.detectType(str);
|
||||
const type = detectType(str);
|
||||
expect(type).toBe('flowchart');
|
||||
});
|
||||
it('should handle a graph definition for gitGraph', function () {
|
||||
const str = ' \n gitGraph TB:\nbfs1:queue';
|
||||
const type = utils.detectType(str);
|
||||
const type = detectType(str);
|
||||
expect(type).toBe('gitGraph');
|
||||
});
|
||||
});
|
||||
|
5
test.js
Normal file
5
test.js
Normal file
@ -0,0 +1,5 @@
|
||||
function apa() {
|
||||
// comment's
|
||||
const a = 1;
|
||||
return 'apa' + a;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user