mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-10-24 00:14:10 +02:00
@@ -70,7 +70,7 @@ describe('Interaction', () => {
|
|||||||
expect(location.href).to.eq('http://localhost:9000/webpackUsage.html');
|
expect(location.href).to.eq('http://localhost:9000/webpackUsage.html');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('should handle a click on a task with a bound function', () => {
|
it('should handle a click on a task with a bound function without args', () => {
|
||||||
const url = 'http://localhost:9000/click_security_loose.html';
|
const url = 'http://localhost:9000/click_security_loose.html';
|
||||||
cy.viewport(1440, 1024);
|
cy.viewport(1440, 1024);
|
||||||
cy.visit(url);
|
cy.visit(url);
|
||||||
@@ -78,9 +78,20 @@ describe('Interaction', () => {
|
|||||||
.find('rect#cl2')
|
.find('rect#cl2')
|
||||||
.click({ force: true });
|
.click({ force: true });
|
||||||
|
|
||||||
cy.get('.created-by-gant-click').should('have.text', 'Clicked By Gant');
|
cy.get('.created-by-gant-click').should('have.text', 'Clicked By Gant cl2');
|
||||||
});
|
});
|
||||||
it('should handle a click on a task with a bound function', () => {
|
it('should handle a click on a task with a bound function with args', () => {
|
||||||
|
const url = 'http://localhost:9000/click_security_loose.html';
|
||||||
|
cy.viewport(1440, 1024);
|
||||||
|
cy.visit(url);
|
||||||
|
cy.get('body')
|
||||||
|
.find('rect#cl3')
|
||||||
|
.click({ force: true });
|
||||||
|
|
||||||
|
cy.get('.created-by-gant-click').should('have.text', 'Clicked By Gant test1 test2 test3');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle a click on a task with a bound function without args', () => {
|
||||||
const url = 'http://localhost:9000/click_security_loose.html';
|
const url = 'http://localhost:9000/click_security_loose.html';
|
||||||
cy.viewport(1440, 1024);
|
cy.viewport(1440, 1024);
|
||||||
cy.visit(url);
|
cy.visit(url);
|
||||||
@@ -88,8 +99,19 @@ describe('Interaction', () => {
|
|||||||
.find('text#cl2-text')
|
.find('text#cl2-text')
|
||||||
.click({ force: true });
|
.click({ force: true });
|
||||||
|
|
||||||
cy.get('.created-by-gant-click').should('have.text', 'Clicked By Gant');
|
cy.get('.created-by-gant-click').should('have.text', 'Clicked By Gant cl2');
|
||||||
});
|
});
|
||||||
|
it('should handle a click on a task with a bound function with args ', () => {
|
||||||
|
const url = 'http://localhost:9000/click_security_loose.html';
|
||||||
|
cy.viewport(1440, 1024);
|
||||||
|
cy.visit(url);
|
||||||
|
cy.get('body')
|
||||||
|
.find('text#cl3-text')
|
||||||
|
.click({ force: true });
|
||||||
|
|
||||||
|
cy.get('.created-by-gant-click').should('have.text', 'Clicked By Gant test1 test2 test3');
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Interaction - security level tight', () => {
|
describe('Interaction - security level tight', () => {
|
||||||
@@ -170,7 +192,7 @@ describe('Interaction', () => {
|
|||||||
.find('rect#cl2')
|
.find('rect#cl2')
|
||||||
.click({ force: true });
|
.click({ force: true });
|
||||||
|
|
||||||
cy.get('.created-by-gant-click').should('not.have.text', 'Clicked By Gant');
|
cy.get('.created-by-gant-click').should('not.have.text', 'Clicked By Gant cl2');
|
||||||
});
|
});
|
||||||
it('should handle a click on a task with a bound function', () => {
|
it('should handle a click on a task with a bound function', () => {
|
||||||
const url = 'http://localhost:9000/click_security_strict.html';
|
const url = 'http://localhost:9000/click_security_strict.html';
|
||||||
@@ -180,7 +202,7 @@ describe('Interaction', () => {
|
|||||||
.find('text#cl2-text')
|
.find('text#cl2-text')
|
||||||
.click({ force: true });
|
.click({ force: true });
|
||||||
|
|
||||||
cy.get('.created-by-gant-click').should('not.have.text', 'Clicked By Gant');
|
cy.get('.created-by-gant-click').should('not.have.text', 'Clicked By Gant cl2');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -226,7 +248,7 @@ describe('Interaction', () => {
|
|||||||
.find('rect#cl2')
|
.find('rect#cl2')
|
||||||
.click({ force: true });
|
.click({ force: true });
|
||||||
|
|
||||||
cy.get('.created-by-gant-click').should('not.have.text', 'Clicked By Gant');
|
cy.get('.created-by-gant-click').should('not.have.text', 'Clicked By Gant cl2');
|
||||||
});
|
});
|
||||||
it('should handle a click on a task with a bound function', () => {
|
it('should handle a click on a task with a bound function', () => {
|
||||||
const url = 'http://localhost:9000/click_security_strict.html';
|
const url = 'http://localhost:9000/click_security_strict.html';
|
||||||
@@ -236,7 +258,7 @@ describe('Interaction', () => {
|
|||||||
.find('text#cl2-text')
|
.find('text#cl2-text')
|
||||||
.click({ force: true });
|
.click({ force: true });
|
||||||
|
|
||||||
cy.get('.created-by-gant-click').should('not.have.text', 'Clicked By Gant');
|
cy.get('.created-by-gant-click').should('not.have.text', 'Clicked By Gant cl2');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -228,4 +228,48 @@ describe('Class diagram', () => {
|
|||||||
);
|
);
|
||||||
cy.get('svg');
|
cy.get('svg');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('9: should render a simple class diagram with clickable link', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
classDiagram
|
||||||
|
Class01~T~ <|-- AveryLongClass : Cool
|
||||||
|
Class03~T~ *-- Class04~T~
|
||||||
|
Class01 : size()
|
||||||
|
Class01 : int chimp
|
||||||
|
Class01 : int gorilla
|
||||||
|
Class08 <--> C2: Cool label
|
||||||
|
class Class10~T~ {
|
||||||
|
<<service>>
|
||||||
|
int id
|
||||||
|
test()
|
||||||
|
}
|
||||||
|
link class01 "google.com" "A Tooltip"
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
cy.get('svg');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('10: should render a simple class diagram with clickable callback', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
classDiagram
|
||||||
|
Class01~T~ <|-- AveryLongClass : Cool
|
||||||
|
Class03~T~ *-- Class04~T~
|
||||||
|
Class01 : size()
|
||||||
|
Class01 : int chimp
|
||||||
|
Class01 : int gorilla
|
||||||
|
Class08 <--> C2: Cool label
|
||||||
|
class Class10~T~ {
|
||||||
|
<<service>>
|
||||||
|
int id
|
||||||
|
test()
|
||||||
|
}
|
||||||
|
callback class01 "functionCall" "A Tooltip"
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
cy.get('svg');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/* eslint-env jest */
|
/* eslint-env jest */
|
||||||
import { imgSnapshotTest } from '../../helpers/util';
|
import { imgSnapshotTest } from '../../helpers/util';
|
||||||
|
|
||||||
describe('Flowcart', () => {
|
describe('Flowchart', () => {
|
||||||
it('1: should render a simple flowchart no htmlLabels', () => {
|
it('1: should render a simple flowchart no htmlLabels', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`graph TD
|
`graph TD
|
||||||
@@ -57,7 +57,7 @@ describe('Flowcart', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('4: should style nodes via a class.', () => {
|
it('5: should style nodes via a class.', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
graph TD
|
graph TD
|
||||||
@@ -73,7 +73,7 @@ describe('Flowcart', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('5: should render a flowchart full of circles', () => {
|
it('6: should render a flowchart full of circles', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
graph LR
|
graph LR
|
||||||
@@ -102,7 +102,7 @@ describe('Flowcart', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('6: should render a flowchart full of icons', () => {
|
it('7: should render a flowchart full of icons', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
graph TD
|
graph TD
|
||||||
@@ -173,7 +173,7 @@ describe('Flowcart', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('7: should render labels with numbers at the start', () => {
|
it('8: should render labels with numbers at the start', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
graph TB;subgraph "number as labels";1;end;
|
graph TB;subgraph "number as labels";1;end;
|
||||||
@@ -182,7 +182,7 @@ describe('Flowcart', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('8: should render subgraphs', () => {
|
it('9: should render subgraphs', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
graph TB
|
graph TB
|
||||||
@@ -194,7 +194,7 @@ describe('Flowcart', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('9: should render subgraphs with a title starting with a digit', () => {
|
it('10: should render subgraphs with a title starting with a digit', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
graph TB
|
graph TB
|
||||||
@@ -206,7 +206,7 @@ describe('Flowcart', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('10: should render styled subgraphs', () => {
|
it('11: should render styled subgraphs', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
graph TB
|
graph TB
|
||||||
@@ -241,7 +241,7 @@ describe('Flowcart', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('11: should render a flowchart with long names and class definitions', () => {
|
it('12: should render a flowchart with long names and class definitions', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`graph LR
|
`graph LR
|
||||||
sid-B3655226-6C29-4D00-B685-3D5C734DC7E1["
|
sid-B3655226-6C29-4D00-B685-3D5C734DC7E1["
|
||||||
@@ -343,7 +343,7 @@ describe('Flowcart', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('12: should render color of styled nodes', () => {
|
it('13: should render color of styled nodes', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
graph LR
|
graph LR
|
||||||
@@ -361,7 +361,7 @@ describe('Flowcart', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('13: should render hexagons', () => {
|
it('14: should render hexagons', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
graph TD
|
graph TD
|
||||||
@@ -383,7 +383,7 @@ describe('Flowcart', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('14: should render a simple flowchart with comments', () => {
|
it('15: should render a simple flowchart with comments', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`graph TD
|
`graph TD
|
||||||
A[Christmas] -->|Get money| B(Go shopping)
|
A[Christmas] -->|Get money| B(Go shopping)
|
||||||
@@ -396,7 +396,7 @@ describe('Flowcart', () => {
|
|||||||
{ flowchart: { htmlLabels: false } }
|
{ flowchart: { htmlLabels: false } }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('15: Render Stadium shape', () => {
|
it('16: Render Stadium shape', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
` graph TD
|
` graph TD
|
||||||
A([stadium shape test])
|
A([stadium shape test])
|
||||||
@@ -412,7 +412,7 @@ describe('Flowcart', () => {
|
|||||||
{ flowchart: { htmlLabels: false } }
|
{ flowchart: { htmlLabels: false } }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('16: Render Stadium shape', () => {
|
it('17: Render multiline texts', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`graph LR
|
`graph LR
|
||||||
A1[Multi<br>Line] -->|Multi<br>Line| B1(Multi<br>Line)
|
A1[Multi<br>Line] -->|Multi<br>Line| B1(Multi<br>Line)
|
||||||
@@ -428,7 +428,7 @@ describe('Flowcart', () => {
|
|||||||
{ flowchart: { htmlLabels: false } }
|
{ flowchart: { htmlLabels: false } }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('17: Chaining of nodes', () => {
|
it('18: Chaining of nodes', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`graph LR
|
`graph LR
|
||||||
a --> b --> c
|
a --> b --> c
|
||||||
@@ -436,21 +436,42 @@ describe('Flowcart', () => {
|
|||||||
{ flowchart: { htmlLabels: false } }
|
{ flowchart: { htmlLabels: false } }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('18: Multiple nodes and chaining in one statement', () => {
|
it('19: Multiple nodes and chaining in one statement', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`graph LR
|
`graph LR
|
||||||
a --> b c--> d
|
a --> b & c--> d
|
||||||
`,
|
`,
|
||||||
{ flowchart: { htmlLabels: false } }
|
{ flowchart: { htmlLabels: false } }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('19: Multiple nodes and chaining in one statement', () => {
|
it('20: Multiple nodes and chaining in one statement', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`graph TD
|
`graph TD
|
||||||
A[ h ] -- hello --> B[" test "]:::exClass C --> D;
|
A[ h ] -- hello --> B[" test "]:::exClass & C --> D;
|
||||||
classDef exClass background:#bbb,border:1px solid red;
|
classDef exClass background:#bbb,border:1px solid red;
|
||||||
`,
|
`,
|
||||||
{ flowchart: { htmlLabels: false } }
|
{ flowchart: { htmlLabels: false } }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('21: Render cylindrical shape', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`graph LR
|
||||||
|
A[(cylindrical<br />shape<br />test)]
|
||||||
|
A -->|Get money| B1[(Go shopping 1)]
|
||||||
|
A -->|Get money| B2[(Go shopping 2)]
|
||||||
|
A -->|Get money| B3[(Go shopping 3)]
|
||||||
|
C[(Let me think...<br />Do I want something for work,<br />something to spend every free second with,<br />or something to get around?)]
|
||||||
|
B1 --> C
|
||||||
|
B2 --> C
|
||||||
|
B3 --> C
|
||||||
|
C -->|One| D[(Laptop)]
|
||||||
|
C -->|Two| E[(iPhone)]
|
||||||
|
C -->|Three| F[(Car)]
|
||||||
|
click A "index.html#link-clicked" "link test"
|
||||||
|
click B testClick "click test"
|
||||||
|
classDef someclass fill:#f96;
|
||||||
|
class A someclass;`,
|
||||||
|
{ flowchart: { htmlLabels: false } }
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -54,4 +54,44 @@ describe('Sequencediagram', () => {
|
|||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('should render a gantt chart for issue #1060', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
gantt
|
||||||
|
excludes weekdays 2017-01-10
|
||||||
|
title Projects Timeline
|
||||||
|
|
||||||
|
section asdf
|
||||||
|
specs :done, :ps, 2019-05-10, 50d
|
||||||
|
Plasma :pc, 2019-06-20, 60d
|
||||||
|
Rollup :or, 2019-08-20, 50d
|
||||||
|
|
||||||
|
section CEL
|
||||||
|
|
||||||
|
plasma-chamber :done, :pc, 2019-05-20, 60d
|
||||||
|
Plasma Implementation (Rust) :por, 2019-06-20, 120d
|
||||||
|
Predicates (Atomic Swap) :pred, 2019-07-20, 60d
|
||||||
|
|
||||||
|
section DEX 💰
|
||||||
|
|
||||||
|
History zkSNARK :hs, 2019-08-10, 40d
|
||||||
|
Exit :vs, after hs, 60d
|
||||||
|
PredicateSpec :ps, 2019-09-1, 20d
|
||||||
|
PlasmaIntegration :pi, after ps,40d
|
||||||
|
|
||||||
|
|
||||||
|
section Events 🏁
|
||||||
|
|
||||||
|
ETHBoston :done, :eb, 2019-09-08, 3d
|
||||||
|
DevCon :active, :dc, 2019-10-08, 3d
|
||||||
|
|
||||||
|
section Plasma Calls & updates ✨
|
||||||
|
OVM :ovm, 2019-07-12, 120d
|
||||||
|
Plasma call 26 :pc26, 2019-08-21, 1d
|
||||||
|
Plasma call 27 :pc27, 2019-09-03, 1d
|
||||||
|
Plasma call 28 :pc28, 2019-09-17, 1d
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -39,12 +39,15 @@ context('Sequence diagram', () => {
|
|||||||
participant 1 as multiline<br>using #lt;br#gt;
|
participant 1 as multiline<br>using #lt;br#gt;
|
||||||
participant 2 as multiline<br/>using #lt;br/#gt;
|
participant 2 as multiline<br/>using #lt;br/#gt;
|
||||||
participant 3 as multiline<br />using #lt;br /#gt;
|
participant 3 as multiline<br />using #lt;br /#gt;
|
||||||
|
participant 4 as multiline<br \t/>using #lt;br \t/#gt;
|
||||||
1->>2: multiline<br>using #lt;br#gt;
|
1->>2: multiline<br>using #lt;br#gt;
|
||||||
note right of 2: multiline<br>using #lt;br#gt;
|
note right of 2: multiline<br>using #lt;br#gt;
|
||||||
2->>3: multiline<br/>using #lt;br/#gt;
|
2->>3: multiline<br/>using #lt;br/#gt;
|
||||||
note right of 3: multiline<br/>using #lt;br/#gt;
|
note right of 3: multiline<br/>using #lt;br/#gt;
|
||||||
3->>1: multiline<br />using #lt;br /#gt;
|
3->>4: multiline<br />using #lt;br /#gt;
|
||||||
note right of 1: multiline<br />using #lt;br /#gt;
|
note right of 4: multiline<br />using #lt;br /#gt;
|
||||||
|
4->>1: multiline<br />using #lt;br /#gt;
|
||||||
|
note right of 1: multiline<br \t/>using #lt;br \t/#gt;
|
||||||
`,
|
`,
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
|
@@ -49,9 +49,11 @@
|
|||||||
section Clickable
|
section Clickable
|
||||||
Visit mermaidjs :active, cl1, 2014-01-07,2014-01-10
|
Visit mermaidjs :active, cl1, 2014-01-07,2014-01-10
|
||||||
Calling a Callback (look at the console log) :cl2, after cl1, 3d
|
Calling a Callback (look at the console log) :cl2, after cl1, 3d
|
||||||
|
Calling a Callback with args :cl3, after cl1, 3d
|
||||||
|
|
||||||
click cl1 href "http://localhost:9000/webpackUsage.html"
|
click cl1 href "http://localhost:9000/webpackUsage.html"
|
||||||
click cl2 call clickByGantt("test", test, test)
|
click cl2 call clickByGantt()
|
||||||
|
click cl3 call clickByGantt("test1", test2, test3)
|
||||||
|
|
||||||
section Last section
|
section Last section
|
||||||
Describe gantt syntax :after doc1, 3d
|
Describe gantt syntax :after doc1, 3d
|
||||||
@@ -69,11 +71,14 @@
|
|||||||
|
|
||||||
document.getElementsByTagName('body')[0].appendChild(div)
|
document.getElementsByTagName('body')[0].appendChild(div)
|
||||||
}
|
}
|
||||||
function clickByGantt(elemName) {
|
function clickByGantt(arg1, arg2, arg3) {
|
||||||
const div = document.createElement('div')
|
const div = document.createElement('div')
|
||||||
div.className = 'created-by-gant-click'
|
div.className = 'created-by-gant-click'
|
||||||
div.style = 'padding: 20px; background: green; color: white;'
|
div.style = 'padding: 20px; background: green; color: white;'
|
||||||
div.innerText = 'Clicked By Gant'
|
div.innerText = 'Clicked By Gant'
|
||||||
|
if (arg1) div.innerText += ' ' + arg1;
|
||||||
|
if (arg2) div.innerText += ' ' + arg2;
|
||||||
|
if (arg3) div.innerText += ' ' + arg3;
|
||||||
|
|
||||||
document.getElementsByTagName('body')[0].appendChild(div)
|
document.getElementsByTagName('body')[0].appendChild(div)
|
||||||
}
|
}
|
||||||
|
@@ -49,9 +49,11 @@
|
|||||||
section Clickable
|
section Clickable
|
||||||
Visit mermaidjs :active, cl1, 2014-01-07,2014-01-10
|
Visit mermaidjs :active, cl1, 2014-01-07,2014-01-10
|
||||||
Calling a Callback (look at the console log) :cl2, after cl1, 3d
|
Calling a Callback (look at the console log) :cl2, after cl1, 3d
|
||||||
|
Calling a Callback with args :cl3, after cl1, 3d
|
||||||
|
|
||||||
click cl1 href "http://localhost:9000/webpackUsage.html"
|
click cl1 href "http://localhost:9000/webpackUsage.html"
|
||||||
click cl2 call clickByGantt("test", test, test)
|
click cl2 call clickByGantt()
|
||||||
|
click cl3 call clickByGantt("test1", test2, test3)
|
||||||
|
|
||||||
section Last section
|
section Last section
|
||||||
Describe gantt syntax :after doc1, 3d
|
Describe gantt syntax :after doc1, 3d
|
||||||
@@ -69,11 +71,14 @@
|
|||||||
|
|
||||||
document.getElementsByTagName('body')[0].appendChild(div)
|
document.getElementsByTagName('body')[0].appendChild(div)
|
||||||
}
|
}
|
||||||
function clickByGantt(elemName) {
|
function clickByGantt(arg1, arg2, arg3) {
|
||||||
const div = document.createElement('div')
|
const div = document.createElement('div')
|
||||||
div.className = 'created-by-gant-click'
|
div.className = 'created-by-gant-click'
|
||||||
div.style = 'padding: 20px; background: green; color: white;'
|
div.style = 'padding: 20px; background: green; color: white;'
|
||||||
div.innerText = 'Clicked By Gant'
|
div.innerText = 'Clicked By Gant'
|
||||||
|
if (arg1) div.innerText += ' ' + arg1;
|
||||||
|
if (arg2) div.innerText += ' ' + arg2;
|
||||||
|
if (arg3) div.innerText += ' ' + arg3;
|
||||||
|
|
||||||
document.getElementsByTagName('body')[0].appendChild(div)
|
document.getElementsByTagName('body')[0].appendChild(div)
|
||||||
}
|
}
|
||||||
|
23
dist/index.html
vendored
23
dist/index.html
vendored
@@ -313,6 +313,24 @@ class A someclass;
|
|||||||
classDef someclass fill:#f96;
|
classDef someclass fill:#f96;
|
||||||
class A someclass;
|
class A someclass;
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mermaid">
|
||||||
|
graph LR
|
||||||
|
A[(cylindrical<br />shape<br />test)]
|
||||||
|
A -->|Get money| B1[(Go shopping 1)]
|
||||||
|
A -->|Get money| B2[(Go shopping 2)]
|
||||||
|
A -->|Get money| B3[(Go shopping 3)]
|
||||||
|
C[(Let me think...<br />Do I want something for work,<br />something to spend every free second with,<br />or something to get around?)]
|
||||||
|
B1 --> C
|
||||||
|
B2 --> C
|
||||||
|
B3 --> C
|
||||||
|
C -->|One| D[(Laptop)]
|
||||||
|
C -->|Two| E[(iPhone)]
|
||||||
|
C -->|Three| F[(Car)]
|
||||||
|
click A "index.html#link-clicked" "link test"
|
||||||
|
click B testClick "click test"
|
||||||
|
classDef someclass fill:#f96;
|
||||||
|
class A someclass;
|
||||||
|
</div>
|
||||||
<div class="mermaid">
|
<div class="mermaid">
|
||||||
graph LR
|
graph LR
|
||||||
A1[Multi<br>Line] -->|Multi<br>Line| B1(Multi<br>Line)
|
A1[Multi<br>Line] -->|Multi<br>Line| B1(Multi<br>Line)
|
||||||
@@ -361,11 +379,14 @@ end
|
|||||||
participant 1 as multiline<br>using #lt;br#gt;
|
participant 1 as multiline<br>using #lt;br#gt;
|
||||||
participant 2 as multiline<br/>using #lt;br/#gt;
|
participant 2 as multiline<br/>using #lt;br/#gt;
|
||||||
participant 3 as multiline<br />using #lt;br /#gt;
|
participant 3 as multiline<br />using #lt;br /#gt;
|
||||||
|
participant 4 as multiline<br />using #lt;br /#gt;
|
||||||
1->>2: multiline<br>using #lt;br#gt;
|
1->>2: multiline<br>using #lt;br#gt;
|
||||||
note right of 2: multiline<br>using #lt;br#gt;
|
note right of 2: multiline<br>using #lt;br#gt;
|
||||||
2->>3: multiline<br/>using #lt;br/#gt;
|
2->>3: multiline<br/>using #lt;br/#gt;
|
||||||
note right of 3: multiline<br/>using #lt;br/#gt;
|
note right of 3: multiline<br/>using #lt;br/#gt;
|
||||||
3->>1: multiline<br />using #lt;br /#gt;
|
3->>4: multiline<br />using #lt;br /#gt;
|
||||||
|
note right of 4: multiline<br />using #lt;br /#gt;
|
||||||
|
4->>1: multiline<br />using #lt;br /#gt;
|
||||||
note right of 1: multiline<br />using #lt;br /#gt;
|
note right of 1: multiline<br />using #lt;br /#gt;
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@@ -89,6 +89,17 @@ graph LR
|
|||||||
id1([This is the text in the box])
|
id1([This is the text in the box])
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### A node in a cylindrical shape
|
||||||
|
|
||||||
|
```
|
||||||
|
graph LR
|
||||||
|
id1[(Database)]
|
||||||
|
```
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
id1[(Database)]
|
||||||
|
```
|
||||||
|
|
||||||
### A node in the form of a circle
|
### A node in the form of a circle
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@@ -302,3 +302,48 @@ Param | Descriotion | Default value
|
|||||||
--- | --- | ---
|
--- | --- | ---
|
||||||
mirrorActor|Turns on/off the rendering of actors below the diagram as well as above it|false
|
mirrorActor|Turns on/off the rendering of actors below the diagram as well as above it|false
|
||||||
bottomMarginAdj|Adjusts how far down the graph ended. Wide borders styles with css could generate unwantewd clipping which is why this config param exists.|1
|
bottomMarginAdj|Adjusts how far down the graph ended. Wide borders styles with css could generate unwantewd clipping which is why this config param exists.|1
|
||||||
|
|
||||||
|
## Interaction
|
||||||
|
|
||||||
|
It is possible to bind a click event to a task, the click can lead to either a javascript callback or to a link which will be opened in the current browser tab. **Note**: This functionality is disabled when using `securityLevel='strict'` and enabled when using `securityLevel='loose'`.
|
||||||
|
|
||||||
|
```
|
||||||
|
click taskId call callback(arguments)
|
||||||
|
click taskId href URL
|
||||||
|
```
|
||||||
|
|
||||||
|
* taskId is the id of the task
|
||||||
|
* callback is the name of a javascript function defined on the page displaying the graph, the function will be called with the taskId as the parameter if no other arguments are specified..
|
||||||
|
|
||||||
|
Beginners tip, a full example using interactive links in an html context:
|
||||||
|
```
|
||||||
|
<body>
|
||||||
|
<div class="mermaid">
|
||||||
|
gantt
|
||||||
|
dateFormat YYYY-MM-DD
|
||||||
|
|
||||||
|
section Clickable
|
||||||
|
Visit mermaidjs :active, cl1, 2014-01-07, 3d
|
||||||
|
Print arguments :cl2, after cl1, 3d
|
||||||
|
Print task :cl3, after cl2, 3d
|
||||||
|
|
||||||
|
click cl1 href "https://mermaidjs.github.io/"
|
||||||
|
click cl2 call printArguments("test1", "test2", test3)
|
||||||
|
click cl3 call printTask()
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var printArguments = function(arg1, arg2, arg3) {
|
||||||
|
alert('printArguments called with arguments: ' + arg1 + ', ' + arg2 + ', ' + arg3);
|
||||||
|
}
|
||||||
|
var printTask = function(taskId) {
|
||||||
|
alert('taskId: ' + taskId);
|
||||||
|
}
|
||||||
|
var config = {
|
||||||
|
startOnLoad:true,
|
||||||
|
securityLevel:'loose',
|
||||||
|
};
|
||||||
|
mermaid.initialize(config);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
```
|
||||||
|
@@ -1,8 +1,17 @@
|
|||||||
|
import * as d3 from 'd3';
|
||||||
|
import { sanitizeUrl } from '@braintree/sanitize-url';
|
||||||
import { logger } from '../../logger';
|
import { logger } from '../../logger';
|
||||||
|
import { getConfig } from '../../config';
|
||||||
|
|
||||||
|
const MERMAID_DOM_ID_PREFIX = '';
|
||||||
|
|
||||||
|
const config = getConfig();
|
||||||
|
|
||||||
let relations = [];
|
let relations = [];
|
||||||
let classes = {};
|
let classes = {};
|
||||||
|
|
||||||
|
let funs = [];
|
||||||
|
|
||||||
const splitClassNameAndType = function(id) {
|
const splitClassNameAndType = function(id) {
|
||||||
let genericType = '';
|
let genericType = '';
|
||||||
let className = id;
|
let className = id;
|
||||||
@@ -29,6 +38,7 @@ export const addClass = function(id) {
|
|||||||
classes[classId.className] = {
|
classes[classId.className] = {
|
||||||
id: classId.className,
|
id: classId.className,
|
||||||
type: classId.type,
|
type: classId.type,
|
||||||
|
cssClasses: [],
|
||||||
methods: [],
|
methods: [],
|
||||||
members: [],
|
members: [],
|
||||||
annotations: []
|
annotations: []
|
||||||
@@ -38,6 +48,8 @@ export const addClass = function(id) {
|
|||||||
export const clear = function() {
|
export const clear = function() {
|
||||||
relations = [];
|
relations = [];
|
||||||
classes = {};
|
classes = {};
|
||||||
|
funs = [];
|
||||||
|
funs.push(setupToolTips);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getClass = function(id) {
|
export const getClass = function(id) {
|
||||||
@@ -117,6 +129,91 @@ export const cleanupLabel = function(label) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by parser when a special node is found, e.g. a clickable element.
|
||||||
|
* @param ids Comma separated list of ids
|
||||||
|
* @param className Class to add
|
||||||
|
*/
|
||||||
|
export const setCssClass = function(ids, className) {
|
||||||
|
ids.split(',').forEach(function(_id) {
|
||||||
|
let id = _id;
|
||||||
|
if (_id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id;
|
||||||
|
if (typeof classes[id] !== 'undefined') {
|
||||||
|
classes[id].cssClasses.push(className);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by parser when a link is found. Adds the URL to the vertex data.
|
||||||
|
* @param ids Comma separated list of ids
|
||||||
|
* @param linkStr URL to create a link for
|
||||||
|
* @param tooltip Tooltip for the clickable element
|
||||||
|
*/
|
||||||
|
export const setLink = function(ids, linkStr, tooltip) {
|
||||||
|
ids.split(',').forEach(function(_id) {
|
||||||
|
let id = _id;
|
||||||
|
if (_id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id;
|
||||||
|
if (typeof classes[id] !== 'undefined') {
|
||||||
|
if (config.securityLevel !== 'loose') {
|
||||||
|
classes[id].link = sanitizeUrl(linkStr);
|
||||||
|
} else {
|
||||||
|
classes[id].link = linkStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tooltip) {
|
||||||
|
classes[id].tooltip = tooltip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setCssClass(ids, 'clickable');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by parser when a click definition is found. Registers an event handler.
|
||||||
|
* @param ids Comma separated list of ids
|
||||||
|
* @param functionName Function to be called on click
|
||||||
|
* @param tooltip Tooltip for the clickable element
|
||||||
|
*/
|
||||||
|
export const setClickEvent = function(ids, functionName, tooltip) {
|
||||||
|
ids.split(',').forEach(function(id) {
|
||||||
|
setClickFunc(id, functionName, tooltip);
|
||||||
|
});
|
||||||
|
setCssClass(ids, 'clickable');
|
||||||
|
};
|
||||||
|
|
||||||
|
const setClickFunc = function(_id, functionName) {
|
||||||
|
let id = _id;
|
||||||
|
if (_id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id;
|
||||||
|
if (config.securityLevel !== 'loose') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof functionName === 'undefined') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof classes[id] !== 'undefined') {
|
||||||
|
funs.push(function() {
|
||||||
|
const elem = document.querySelector(`[id="${id}"]`);
|
||||||
|
if (elem !== null) {
|
||||||
|
elem.setAttribute('title', classes[id].tooltip);
|
||||||
|
elem.addEventListener(
|
||||||
|
'click',
|
||||||
|
function() {
|
||||||
|
window[functionName](id);
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const bindFunctions = function(element) {
|
||||||
|
funs.forEach(function(fun) {
|
||||||
|
fun(element);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const lineType = {
|
export const lineType = {
|
||||||
LINE: 0,
|
LINE: 0,
|
||||||
DOTTED_LINE: 1
|
DOTTED_LINE: 1
|
||||||
@@ -129,8 +226,53 @@ export const relationType = {
|
|||||||
DEPENDENCY: 3
|
DEPENDENCY: 3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const setupToolTips = function(element) {
|
||||||
|
let tooltipElem = d3.select('.mermaidTooltip');
|
||||||
|
if ((tooltipElem._groups || tooltipElem)[0][0] === null) {
|
||||||
|
tooltipElem = d3
|
||||||
|
.select('body')
|
||||||
|
.append('div')
|
||||||
|
.attr('class', 'mermaidTooltip')
|
||||||
|
.style('opacity', 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const svg = d3.select(element).select('svg');
|
||||||
|
|
||||||
|
const nodes = svg.selectAll('g.node');
|
||||||
|
nodes
|
||||||
|
.on('mouseover', function() {
|
||||||
|
const el = d3.select(this);
|
||||||
|
const title = el.attr('title');
|
||||||
|
// Dont try to draw a tooltip if no data is provided
|
||||||
|
if (title === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const rect = this.getBoundingClientRect();
|
||||||
|
|
||||||
|
tooltipElem
|
||||||
|
.transition()
|
||||||
|
.duration(200)
|
||||||
|
.style('opacity', '.9');
|
||||||
|
tooltipElem
|
||||||
|
.html(el.attr('title'))
|
||||||
|
.style('left', rect.left + (rect.right - rect.left) / 2 + 'px')
|
||||||
|
.style('top', rect.top - 14 + document.body.scrollTop + 'px');
|
||||||
|
el.classed('hover', true);
|
||||||
|
})
|
||||||
|
.on('mouseout', function() {
|
||||||
|
tooltipElem
|
||||||
|
.transition()
|
||||||
|
.duration(500)
|
||||||
|
.style('opacity', 0);
|
||||||
|
const el = d3.select(this);
|
||||||
|
el.classed('hover', false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
funs.push(setupToolTips);
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
addClass,
|
addClass,
|
||||||
|
bindFunctions,
|
||||||
clear,
|
clear,
|
||||||
getClass,
|
getClass,
|
||||||
getClasses,
|
getClasses,
|
||||||
@@ -141,5 +283,8 @@ export default {
|
|||||||
addMembers,
|
addMembers,
|
||||||
cleanupLabel,
|
cleanupLabel,
|
||||||
lineType,
|
lineType,
|
||||||
relationType
|
relationType,
|
||||||
|
setClickEvent,
|
||||||
|
setCssClass,
|
||||||
|
setLink
|
||||||
};
|
};
|
||||||
|
@@ -250,6 +250,66 @@ describe('class diagram, ', function () {
|
|||||||
|
|
||||||
parser.parse(str);
|
parser.parse(str);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should handle click statement with link', function () {
|
||||||
|
const str =
|
||||||
|
'classDiagram\n' +
|
||||||
|
'class Class1 {\n' +
|
||||||
|
'%% Comment Class01 <|-- Class02\n' +
|
||||||
|
'int : test\n' +
|
||||||
|
'string : foo\n' +
|
||||||
|
'test()\n' +
|
||||||
|
'foo()\n' +
|
||||||
|
'}\n' +
|
||||||
|
'link Class01 "google.com" ';
|
||||||
|
|
||||||
|
parser.parse(str);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle click statement with link and tooltip', function () {
|
||||||
|
const str =
|
||||||
|
'classDiagram\n' +
|
||||||
|
'class Class1 {\n' +
|
||||||
|
'%% Comment Class01 <|-- Class02\n' +
|
||||||
|
'int : test\n' +
|
||||||
|
'string : foo\n' +
|
||||||
|
'test()\n' +
|
||||||
|
'foo()\n' +
|
||||||
|
'}\n' +
|
||||||
|
'link Class01 "google.com" "A Tooltip" ';
|
||||||
|
|
||||||
|
parser.parse(str);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle click statement with callback', function () {
|
||||||
|
const str =
|
||||||
|
'classDiagram\n' +
|
||||||
|
'class Class1 {\n' +
|
||||||
|
'%% Comment Class01 <|-- Class02\n' +
|
||||||
|
'int : test\n' +
|
||||||
|
'string : foo\n' +
|
||||||
|
'test()\n' +
|
||||||
|
'foo()\n' +
|
||||||
|
'}\n' +
|
||||||
|
'callback Class01 "functionCall" ';
|
||||||
|
|
||||||
|
parser.parse(str);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle click statement with callback and tooltip', function () {
|
||||||
|
const str =
|
||||||
|
'classDiagram\n' +
|
||||||
|
'class Class1 {\n' +
|
||||||
|
'%% Comment Class01 <|-- Class02\n' +
|
||||||
|
'int : test\n' +
|
||||||
|
'string : foo\n' +
|
||||||
|
'test()\n' +
|
||||||
|
'foo()\n' +
|
||||||
|
'}\n' +
|
||||||
|
'callback Class01 "functionCall" "A Tooltip" ';
|
||||||
|
|
||||||
|
parser.parse(str);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when fetching data from a classDiagram graph it', function () {
|
describe('when fetching data from a classDiagram graph it', function () {
|
||||||
@@ -464,5 +524,41 @@ describe('class diagram, ', function () {
|
|||||||
expect(testClass.methods.length).toBe(1);
|
expect(testClass.methods.length).toBe(1);
|
||||||
expect(testClass.methods[0]).toBe('someMethod()$');
|
expect(testClass.methods[0]).toBe('someMethod()$');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should associate link and css appropriately', function () {
|
||||||
|
const str = 'classDiagram\n' + 'class Class1\n' + 'Class1 : someMethod()\n' + 'link Class1 "google.com"';
|
||||||
|
parser.parse(str);
|
||||||
|
|
||||||
|
const testClass = parser.yy.getClass('Class1');
|
||||||
|
expect(testClass.link).toBe('about:blank');//('google.com'); security needs to be set to 'loose' for this to work right
|
||||||
|
expect(testClass.cssClasses.length).toBe(1);
|
||||||
|
expect(testClass.cssClasses[0]).toBe('clickable');
|
||||||
|
});
|
||||||
|
it('should associate link with tooltip', function () {
|
||||||
|
const str = 'classDiagram\n' + 'class Class1\n' + 'Class1 : someMethod()\n' + 'link Class1 "google.com" "A tooltip"';
|
||||||
|
parser.parse(str);
|
||||||
|
|
||||||
|
const testClass = parser.yy.getClass('Class1');
|
||||||
|
expect(testClass.link).toBe('about:blank');//('google.com'); security needs to be set to 'loose' for this to work right
|
||||||
|
expect(testClass.tooltip).toBe('A tooltip');
|
||||||
|
expect(testClass.cssClasses.length).toBe(1);
|
||||||
|
expect(testClass.cssClasses[0]).toBe('clickable');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should associate callback appropriately', function () {
|
||||||
|
spyOn(classDb, 'setClickEvent');
|
||||||
|
const str = 'classDiagram\n' + 'class Class1\n' + 'Class1 : someMethod()\n' + 'callback Class1 "functionCall"';
|
||||||
|
parser.parse(str);
|
||||||
|
|
||||||
|
expect(classDb.setClickEvent).toHaveBeenCalledWith('Class1', 'functionCall', undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should associate callback with tooltip', function () {
|
||||||
|
spyOn(classDb, 'setClickEvent');
|
||||||
|
const str = 'classDiagram\n' + 'class Class1\n' + 'Class1 : someMethod()\n' + 'callback Class1 "functionCall" "A tooltip"';
|
||||||
|
parser.parse(str);
|
||||||
|
|
||||||
|
expect(classDb.setClickEvent).toHaveBeenCalledWith('Class1', 'functionCall', 'A tooltip');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -280,6 +280,11 @@ const drawEdge = function(elem, path, relation) {
|
|||||||
const drawClass = function(elem, classDef) {
|
const drawClass = function(elem, classDef) {
|
||||||
logger.info('Rendering class ' + classDef);
|
logger.info('Rendering class ' + classDef);
|
||||||
|
|
||||||
|
let cssClassStr = 'classGroup ';
|
||||||
|
if (classDef.cssClasses.length > 0) {
|
||||||
|
cssClassStr = cssClassStr + classDef.cssClasses.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
const addTspan = function(textEl, txt, isFirst) {
|
const addTspan = function(textEl, txt, isFirst) {
|
||||||
let displayText = txt;
|
let displayText = txt;
|
||||||
let cssStyle = '';
|
let cssStyle = '';
|
||||||
@@ -326,13 +331,25 @@ const drawClass = function(elem, classDef) {
|
|||||||
const g = elem
|
const g = elem
|
||||||
.append('g')
|
.append('g')
|
||||||
.attr('id', id)
|
.attr('id', id)
|
||||||
.attr('class', 'classGroup');
|
.attr('class', cssClassStr);
|
||||||
|
|
||||||
// add title
|
// add title
|
||||||
const title = g
|
let title;
|
||||||
|
if (classDef.link) {
|
||||||
|
title = g
|
||||||
|
.append('svg:a')
|
||||||
|
.attr('xlink:href', classDef.link)
|
||||||
|
.attr('xlink:target', '_blank')
|
||||||
|
.attr('xlink:title', classDef.tooltip)
|
||||||
.append('text')
|
.append('text')
|
||||||
.attr('y', conf.textHeight + conf.padding)
|
.attr('y', conf.textHeight + conf.padding)
|
||||||
.attr('x', 0);
|
.attr('x', 0);
|
||||||
|
} else {
|
||||||
|
title = g
|
||||||
|
.append('text')
|
||||||
|
.attr('y', conf.textHeight + conf.padding)
|
||||||
|
.attr('x', 0);
|
||||||
|
}
|
||||||
|
|
||||||
// add annotations
|
// add annotations
|
||||||
let isFirst = true;
|
let isFirst = true;
|
||||||
@@ -348,7 +365,6 @@ const drawClass = function(elem, classDef) {
|
|||||||
classTitleString += '<' + classDef.type + '>';
|
classTitleString += '<' + classDef.type + '>';
|
||||||
}
|
}
|
||||||
|
|
||||||
// add class title
|
|
||||||
const classTitle = title
|
const classTitle = title
|
||||||
.append('tspan')
|
.append('tspan')
|
||||||
.text(classTitleString)
|
.text(classTitleString)
|
||||||
@@ -434,6 +450,7 @@ export const setConf = function(cnf) {
|
|||||||
conf[key] = cnf[key];
|
conf[key] = cnf[key];
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws a flowchart in the tag with id: id based on the graph definition in text.
|
* Draws a flowchart in the tag with id: id based on the graph definition in text.
|
||||||
* @param text
|
* @param text
|
||||||
@@ -470,10 +487,12 @@ export const draw = function(text, id) {
|
|||||||
for (let i = 0; i < keys.length; i++) {
|
for (let i = 0; i < keys.length; i++) {
|
||||||
const classDef = classes[keys[i]];
|
const classDef = classes[keys[i]];
|
||||||
const node = drawClass(diagram, classDef);
|
const node = drawClass(diagram, classDef);
|
||||||
|
|
||||||
// Add nodes to the graph. The first argument is the node id. The second is
|
// Add nodes to the graph. The first argument is the node id. The second is
|
||||||
// metadata about the node. In this case we're going to add labels to each of
|
// metadata about the node. In this case we're going to add labels to each of
|
||||||
// our nodes.
|
// our nodes.
|
||||||
g.setNode(node.id, node);
|
g.setNode(node.id, node);
|
||||||
|
|
||||||
logger.info('Org height: ' + node.height);
|
logger.info('Org height: ' + node.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -21,6 +21,9 @@
|
|||||||
|
|
||||||
|
|
||||||
"class" return 'CLASS';
|
"class" return 'CLASS';
|
||||||
|
//"click" return 'CLICK';
|
||||||
|
"callback" return 'CALLBACK';
|
||||||
|
"link" return 'LINK';
|
||||||
"<<" return 'ANNOTATION_START';
|
"<<" return 'ANNOTATION_START';
|
||||||
">>" return 'ANNOTATION_END';
|
">>" return 'ANNOTATION_END';
|
||||||
[~] this.begin("generic");
|
[~] this.begin("generic");
|
||||||
@@ -149,6 +152,7 @@ statement
|
|||||||
| classStatement
|
| classStatement
|
||||||
| methodStatement
|
| methodStatement
|
||||||
| annotationStatement
|
| annotationStatement
|
||||||
|
| clickStatement
|
||||||
;
|
;
|
||||||
|
|
||||||
classStatement
|
classStatement
|
||||||
@@ -198,6 +202,13 @@ lineType
|
|||||||
| DOTTED_LINE {$$=yy.lineType.DOTTED_LINE;}
|
| DOTTED_LINE {$$=yy.lineType.DOTTED_LINE;}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
clickStatement
|
||||||
|
: CALLBACK className STR {$$ = $1;yy.setClickEvent($2, $3, undefined);}
|
||||||
|
| CALLBACK className STR STR {$$ = $1;yy.setClickEvent($2, $3, $4);}
|
||||||
|
| LINK className STR {$$ = $1;yy.setLink($2, $3, undefined);}
|
||||||
|
| LINK className STR STR {$$ = $1;yy.setLink($2, $3, $4);}
|
||||||
|
;
|
||||||
|
|
||||||
commentToken : textToken | graphCodeTokens ;
|
commentToken : textToken | graphCodeTokens ;
|
||||||
|
|
||||||
textToken : textNoTagsToken | TAGSTART | TAGEND | '==' | '--' | PCT | DEFAULT;
|
textToken : textNoTagsToken | TAGSTART | TAGEND | '==' | '--' | PCT | DEFAULT;
|
||||||
|
@@ -154,10 +154,74 @@ function stadium(parent, bbox, node) {
|
|||||||
return shapeSvg;
|
return shapeSvg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cylinder(parent, bbox, node) {
|
||||||
|
const w = bbox.width;
|
||||||
|
const rx = w / 2;
|
||||||
|
const ry = rx / (2.5 + w / 50);
|
||||||
|
const h = bbox.height + ry;
|
||||||
|
|
||||||
|
const shape =
|
||||||
|
'M 0,' +
|
||||||
|
ry +
|
||||||
|
' a ' +
|
||||||
|
rx +
|
||||||
|
',' +
|
||||||
|
ry +
|
||||||
|
' 0,0,0 ' +
|
||||||
|
w +
|
||||||
|
' 0 a ' +
|
||||||
|
rx +
|
||||||
|
',' +
|
||||||
|
ry +
|
||||||
|
' 0,0,0 ' +
|
||||||
|
-w +
|
||||||
|
' 0 l 0,' +
|
||||||
|
h +
|
||||||
|
' a ' +
|
||||||
|
rx +
|
||||||
|
',' +
|
||||||
|
ry +
|
||||||
|
' 0,0,0 ' +
|
||||||
|
w +
|
||||||
|
' 0 l 0,' +
|
||||||
|
-h;
|
||||||
|
|
||||||
|
const shapeSvg = parent
|
||||||
|
.attr('label-offset-y', ry)
|
||||||
|
.insert('path', ':first-child')
|
||||||
|
.attr('d', shape)
|
||||||
|
.attr('transform', 'translate(' + -w / 2 + ',' + -(h / 2 + ry) + ')');
|
||||||
|
|
||||||
|
node.intersect = function(point) {
|
||||||
|
const pos = dagreD3.intersect.rect(node, point);
|
||||||
|
const x = pos.x - node.x;
|
||||||
|
|
||||||
|
if (
|
||||||
|
rx != 0 &&
|
||||||
|
(Math.abs(x) < node.width / 2 ||
|
||||||
|
(Math.abs(x) == node.width / 2 && Math.abs(pos.y - node.y) > node.height / 2 - ry))
|
||||||
|
) {
|
||||||
|
// ellipsis equation: x*x / a*a + y*y / b*b = 1
|
||||||
|
// solve for y to get adjustion value for pos.y
|
||||||
|
let y = ry * ry * (1 - (x * x) / (rx * rx));
|
||||||
|
if (y != 0) y = Math.sqrt(y);
|
||||||
|
y = ry - y;
|
||||||
|
if (point.y - node.y > 0) y = -y;
|
||||||
|
|
||||||
|
pos.y += y;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
return shapeSvg;
|
||||||
|
}
|
||||||
|
|
||||||
export function addToRender(render) {
|
export function addToRender(render) {
|
||||||
render.shapes().question = question;
|
render.shapes().question = question;
|
||||||
render.shapes().hexagon = hexagon;
|
render.shapes().hexagon = hexagon;
|
||||||
render.shapes().stadium = stadium;
|
render.shapes().stadium = stadium;
|
||||||
|
render.shapes().cylinder = cylinder;
|
||||||
|
|
||||||
// Add custom shape for box with inverted arrow on left side
|
// Add custom shape for box with inverted arrow on left side
|
||||||
render.shapes().rect_left_inv_arrow = rect_left_inv_arrow;
|
render.shapes().rect_left_inv_arrow = rect_left_inv_arrow;
|
||||||
|
@@ -23,6 +23,23 @@ describe('flowchart shapes', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// path-based shapes
|
||||||
|
[
|
||||||
|
['cylinder', useWidth, useHeight]
|
||||||
|
].forEach(function([shapeType, getW, getH]) {
|
||||||
|
it(`should add a ${shapeType} shape that renders a properly positioned path element`, function() {
|
||||||
|
const mockRender = MockRender();
|
||||||
|
const mockSvg = MockSvg();
|
||||||
|
addToRender(mockRender);
|
||||||
|
|
||||||
|
[[100, 100], [123, 45], [71, 300]].forEach(function([width, height]) {
|
||||||
|
const shape = mockRender.shapes()[shapeType](mockSvg, { width, height }, {});
|
||||||
|
expect(shape.__tag).toEqual('path');
|
||||||
|
expect(shape.__attrs).toHaveProperty('d');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// polygon-based shapes
|
// polygon-based shapes
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
|
@@ -608,7 +608,7 @@ const destructLink = (_str, _startStr) => {
|
|||||||
let startInfo;
|
let startInfo;
|
||||||
if (_startStr) {
|
if (_startStr) {
|
||||||
startInfo = destructStartLink(_startStr);
|
startInfo = destructStartLink(_startStr);
|
||||||
console.log(startInfo, info);
|
|
||||||
if (startInfo.stroke !== info.stroke) {
|
if (startInfo.stroke !== info.stroke) {
|
||||||
return { type: 'INVALID', stroke: 'INVALID' };
|
return { type: 'INVALID', stroke: 'INVALID' };
|
||||||
}
|
}
|
||||||
|
@@ -104,15 +104,6 @@ export const addVertices = function(vert, g, svgId) {
|
|||||||
vertexNode = svgLabel;
|
vertexNode = svgLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the node has a link, we wrap it in a SVG link
|
|
||||||
if (vertex.link) {
|
|
||||||
const link = document.createElementNS('http://www.w3.org/2000/svg', 'a');
|
|
||||||
link.setAttributeNS('http://www.w3.org/2000/svg', 'href', vertex.link);
|
|
||||||
link.setAttributeNS('http://www.w3.org/2000/svg', 'rel', 'noopener');
|
|
||||||
link.appendChild(vertexNode);
|
|
||||||
vertexNode = link;
|
|
||||||
}
|
|
||||||
|
|
||||||
let radious = 0;
|
let radious = 0;
|
||||||
let _shape = '';
|
let _shape = '';
|
||||||
// Set the shape based parameters
|
// Set the shape based parameters
|
||||||
@@ -157,6 +148,9 @@ export const addVertices = function(vert, g, svgId) {
|
|||||||
case 'stadium':
|
case 'stadium':
|
||||||
_shape = 'stadium';
|
_shape = 'stadium';
|
||||||
break;
|
break;
|
||||||
|
case 'cylinder':
|
||||||
|
_shape = 'cylinder';
|
||||||
|
break;
|
||||||
case 'group':
|
case 'group':
|
||||||
_shape = 'rect';
|
_shape = 'rect';
|
||||||
break;
|
break;
|
||||||
@@ -246,7 +240,7 @@ export const addEdges = function(edges, g) {
|
|||||||
edgeData.label = '<span class="edgeLabel">' + edge.text + '</span>';
|
edgeData.label = '<span class="edgeLabel">' + edge.text + '</span>';
|
||||||
} else {
|
} else {
|
||||||
edgeData.labelType = 'text';
|
edgeData.labelType = 'text';
|
||||||
edgeData.label = edge.text.replace(/<br ?\/?>/g, '\n');
|
edgeData.label = edge.text.replace(/<br\s*\/?>/g, '\n');
|
||||||
|
|
||||||
if (typeof edge.style === 'undefined') {
|
if (typeof edge.style === 'undefined') {
|
||||||
edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none';
|
edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none';
|
||||||
@@ -494,6 +488,39 @@ export const draw = function(text, id) {
|
|||||||
label.insertBefore(rect, label.firstChild);
|
label.insertBefore(rect, label.firstChild);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If node has a link, wrap it in an anchor SVG object.
|
||||||
|
const keys = Object.keys(vert);
|
||||||
|
keys.forEach(function(key) {
|
||||||
|
const vertex = vert[key];
|
||||||
|
|
||||||
|
if (vertex.link) {
|
||||||
|
const node = d3.select('#' + id + ' [id="' + key + '"]');
|
||||||
|
if (node) {
|
||||||
|
const link = document.createElementNS('http://www.w3.org/2000/svg', 'a');
|
||||||
|
link.setAttributeNS('http://www.w3.org/2000/svg', 'href', vertex.link);
|
||||||
|
link.setAttributeNS('http://www.w3.org/2000/svg', 'rel', 'noopener');
|
||||||
|
|
||||||
|
const linkNode = node.insert(function() {
|
||||||
|
return link;
|
||||||
|
}, ':first-child');
|
||||||
|
|
||||||
|
const shape = node.select('.label-container');
|
||||||
|
if (shape) {
|
||||||
|
linkNode.append(function() {
|
||||||
|
return shape.node();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const label = node.select('.label');
|
||||||
|
if (label) {
|
||||||
|
linkNode.append(function() {
|
||||||
|
return label.node();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@@ -23,6 +23,7 @@ describe('the flowchart renderer', function() {
|
|||||||
['circle', 'circle'],
|
['circle', 'circle'],
|
||||||
['ellipse', 'ellipse'],
|
['ellipse', 'ellipse'],
|
||||||
['stadium', 'stadium'],
|
['stadium', 'stadium'],
|
||||||
|
['cylinder', 'cylinder'],
|
||||||
['group', 'rect']
|
['group', 'rect']
|
||||||
].forEach(function([type, expectedShape, expectedRadios = 0]) {
|
].forEach(function([type, expectedShape, expectedRadios = 0]) {
|
||||||
it(`should add the correct shaped node to the graph for vertex type ${type}`, function() {
|
it(`should add the correct shaped node to the graph for vertex type ${type}`, function() {
|
||||||
|
@@ -37,7 +37,7 @@ describe('when parsing flowcharts', function() {
|
|||||||
it('should handle chaining of vertices', function() {
|
it('should handle chaining of vertices', function() {
|
||||||
const res = flow.parser.parse(`
|
const res = flow.parser.parse(`
|
||||||
graph TD
|
graph TD
|
||||||
A B --> C;
|
A & B --> C;
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const vert = flow.parser.yy.getVertices();
|
const vert = flow.parser.yy.getVertices();
|
||||||
@@ -59,7 +59,7 @@ describe('when parsing flowcharts', function() {
|
|||||||
it('should multiple vertices in link statement in the begining', function() {
|
it('should multiple vertices in link statement in the begining', function() {
|
||||||
const res = flow.parser.parse(`
|
const res = flow.parser.parse(`
|
||||||
graph TD
|
graph TD
|
||||||
A-->B C;
|
A-->B & C;
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const vert = flow.parser.yy.getVertices();
|
const vert = flow.parser.yy.getVertices();
|
||||||
@@ -81,7 +81,7 @@ describe('when parsing flowcharts', function() {
|
|||||||
it('should multiple vertices in link statement at the end', function() {
|
it('should multiple vertices in link statement at the end', function() {
|
||||||
const res = flow.parser.parse(`
|
const res = flow.parser.parse(`
|
||||||
graph TD
|
graph TD
|
||||||
A B--> C D;
|
A & B--> C & D;
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const vert = flow.parser.yy.getVertices();
|
const vert = flow.parser.yy.getVertices();
|
||||||
@@ -112,7 +112,7 @@ describe('when parsing flowcharts', function() {
|
|||||||
it('should handle chaining of vertices at both ends at once', function() {
|
it('should handle chaining of vertices at both ends at once', function() {
|
||||||
const res = flow.parser.parse(`
|
const res = flow.parser.parse(`
|
||||||
graph TD
|
graph TD
|
||||||
A B--> C D;
|
A & B--> C & D;
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const vert = flow.parser.yy.getVertices();
|
const vert = flow.parser.yy.getVertices();
|
||||||
@@ -140,10 +140,10 @@ describe('when parsing flowcharts', function() {
|
|||||||
expect(edges[3].type).toBe('arrow');
|
expect(edges[3].type).toBe('arrow');
|
||||||
expect(edges[3].text).toBe('');
|
expect(edges[3].text).toBe('');
|
||||||
});
|
});
|
||||||
it('should handle chaining and multiple nodes in in link statement', function() {
|
it('should handle chaining and multiple nodes in in link statement FVC ', function() {
|
||||||
const res = flow.parser.parse(`
|
const res = flow.parser.parse(`
|
||||||
graph TD
|
graph TD
|
||||||
A --> B C --> D;
|
A --> B & B2 & C --> D2;
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const vert = flow.parser.yy.getVertices();
|
const vert = flow.parser.yy.getVertices();
|
||||||
@@ -151,30 +151,39 @@ describe('when parsing flowcharts', function() {
|
|||||||
|
|
||||||
expect(vert['A'].id).toBe('A');
|
expect(vert['A'].id).toBe('A');
|
||||||
expect(vert['B'].id).toBe('B');
|
expect(vert['B'].id).toBe('B');
|
||||||
|
expect(vert['B2'].id).toBe('B2');
|
||||||
expect(vert['C'].id).toBe('C');
|
expect(vert['C'].id).toBe('C');
|
||||||
expect(vert['D'].id).toBe('D');
|
expect(vert['D2'].id).toBe('D2');
|
||||||
expect(edges.length).toBe(4);
|
expect(edges.length).toBe(6);
|
||||||
expect(edges[0].start).toBe('A');
|
expect(edges[0].start).toBe('A');
|
||||||
expect(edges[0].end).toBe('B');
|
expect(edges[0].end).toBe('B');
|
||||||
expect(edges[0].type).toBe('arrow');
|
expect(edges[0].type).toBe('arrow');
|
||||||
expect(edges[0].text).toBe('');
|
expect(edges[0].text).toBe('');
|
||||||
expect(edges[1].start).toBe('A');
|
expect(edges[1].start).toBe('A');
|
||||||
expect(edges[1].end).toBe('C');
|
expect(edges[1].end).toBe('B2');
|
||||||
expect(edges[1].type).toBe('arrow');
|
expect(edges[1].type).toBe('arrow');
|
||||||
expect(edges[1].text).toBe('');
|
expect(edges[1].text).toBe('');
|
||||||
expect(edges[2].start).toBe('B');
|
expect(edges[2].start).toBe('A');
|
||||||
expect(edges[2].end).toBe('D');
|
expect(edges[2].end).toBe('C');
|
||||||
expect(edges[2].type).toBe('arrow');
|
expect(edges[2].type).toBe('arrow');
|
||||||
expect(edges[2].text).toBe('');
|
expect(edges[2].text).toBe('');
|
||||||
expect(edges[3].start).toBe('C');
|
expect(edges[3].start).toBe('B');
|
||||||
expect(edges[3].end).toBe('D');
|
expect(edges[3].end).toBe('D2');
|
||||||
expect(edges[3].type).toBe('arrow');
|
expect(edges[3].type).toBe('arrow');
|
||||||
expect(edges[3].text).toBe('');
|
expect(edges[3].text).toBe('');
|
||||||
|
expect(edges[4].start).toBe('B2');
|
||||||
|
expect(edges[4].end).toBe('D2');
|
||||||
|
expect(edges[4].type).toBe('arrow');
|
||||||
|
expect(edges[4].text).toBe('');
|
||||||
|
expect(edges[5].start).toBe('C');
|
||||||
|
expect(edges[5].end).toBe('D2');
|
||||||
|
expect(edges[5].type).toBe('arrow');
|
||||||
|
expect(edges[5].text).toBe('');
|
||||||
});
|
});
|
||||||
it('should handle chaining and multiple nodes in in link statement with extra info in statements', function() {
|
it('should handle chaining and multiple nodes in in link statement with extra info in statements', function() {
|
||||||
const res = flow.parser.parse(`
|
const res = flow.parser.parse(`
|
||||||
graph TD
|
graph TD
|
||||||
A[ h ] -- hello --> B[" test "]:::exClass C --> D;
|
A[ h ] -- hello --> B[" test "]:::exClass & C --> D;
|
||||||
classDef exClass background:#bbb,border:1px solid red;
|
classDef exClass background:#bbb,border:1px solid red;
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
@@ -38,6 +38,7 @@
|
|||||||
\# return 'BRKT';
|
\# return 'BRKT';
|
||||||
":::" return 'STYLE_SEPARATOR';
|
":::" return 'STYLE_SEPARATOR';
|
||||||
":" return 'COLON';
|
":" return 'COLON';
|
||||||
|
"&" return 'AMP';
|
||||||
";" return 'SEMI';
|
";" return 'SEMI';
|
||||||
"," return 'COMMA';
|
"," return 'COMMA';
|
||||||
"*" return 'MULT';
|
"*" return 'MULT';
|
||||||
@@ -85,6 +86,8 @@
|
|||||||
"-)" return '-)';
|
"-)" return '-)';
|
||||||
"([" return 'STADIUMSTART';
|
"([" return 'STADIUMSTART';
|
||||||
"])" return 'STADIUMEND';
|
"])" return 'STADIUMEND';
|
||||||
|
"[(" return 'CYLINDERSTART';
|
||||||
|
")]" return 'CYLINDEREND';
|
||||||
\- return 'MINUS';
|
\- return 'MINUS';
|
||||||
"." return 'DOT';
|
"." return 'DOT';
|
||||||
[\_] return 'UNDERSCORE';
|
[\_] return 'UNDERSCORE';
|
||||||
@@ -298,8 +301,8 @@ verticeStatement: verticeStatement link node
|
|||||||
|
|
||||||
node: vertex
|
node: vertex
|
||||||
{ /* console.warn('nod', $1); */ $$ = [$1];}
|
{ /* console.warn('nod', $1); */ $$ = [$1];}
|
||||||
| node spaceList vertex
|
| node spaceList AMP spaceList vertex
|
||||||
{ $$ = [$1[0], $3]; /*console.warn('pip', $1, $3, $$);*/ }
|
{ $$ = $1.concat($5); /* console.warn('pip', $1[0], $5, $$); */ }
|
||||||
| vertex STYLE_SEPARATOR idString
|
| vertex STYLE_SEPARATOR idString
|
||||||
{$$ = [$1];yy.setClass($1,$3)}
|
{$$ = [$1];yy.setClass($1,$3)}
|
||||||
;
|
;
|
||||||
@@ -312,6 +315,8 @@ vertex: idString SQS text SQE
|
|||||||
{$$ = $1;yy.addVertex($1,$3,'ellipse');}
|
{$$ = $1;yy.addVertex($1,$3,'ellipse');}
|
||||||
| idString STADIUMSTART text STADIUMEND
|
| idString STADIUMSTART text STADIUMEND
|
||||||
{$$ = $1;yy.addVertex($1,$3,'stadium');}
|
{$$ = $1;yy.addVertex($1,$3,'stadium');}
|
||||||
|
| idString CYLINDERSTART text CYLINDEREND
|
||||||
|
{$$ = $1;yy.addVertex($1,$3,'cylinder');}
|
||||||
| idString PS text PE
|
| idString PS text PE
|
||||||
{$$ = $1;yy.addVertex($1,$3,'round');}
|
{$$ = $1;yy.addVertex($1,$3,'round');}
|
||||||
| idString DIAMOND_START text DIAMOND_STOP
|
| idString DIAMOND_START text DIAMOND_STOP
|
||||||
@@ -464,9 +469,9 @@ alphaNumStatement
|
|||||||
{$$='-';}
|
{$$='-';}
|
||||||
;
|
;
|
||||||
|
|
||||||
alphaNumToken : PUNCTUATION | UNICODE_TEXT | NUM| ALPHA | COLON | COMMA | PLUS | EQUALS | MULT | DOT | BRKT| UNDERSCORE ;
|
alphaNumToken : PUNCTUATION | AMP | UNICODE_TEXT | NUM| ALPHA | COLON | COMMA | PLUS | EQUALS | MULT | DOT | BRKT| UNDERSCORE ;
|
||||||
|
|
||||||
idStringToken : ALPHA|UNDERSCORE |UNICODE_TEXT | NUM| COLON | COMMA | PLUS | MINUS | DOWN |EQUALS | MULT | BRKT | DOT | PUNCTUATION;
|
idStringToken : ALPHA|UNDERSCORE |UNICODE_TEXT | NUM| COLON | COMMA | PLUS | MINUS | DOWN |EQUALS | MULT | BRKT | DOT | PUNCTUATION | AMP;
|
||||||
|
|
||||||
graphCodeTokens: STADIUMSTART | STADIUMEND | TRAPSTART | TRAPEND | INVTRAPSTART | INVTRAPEND | PIPE | PS | PE | SQS | SQE | DIAMOND_START | DIAMOND_STOP | TAGSTART | TAGEND | ARROW_CROSS | ARROW_POINT | ARROW_CIRCLE | ARROW_OPEN | QUOTE | SEMI;
|
graphCodeTokens: STADIUMSTART | STADIUMEND | CYLINDERSTART | CYLINDEREND | TRAPSTART | TRAPEND | INVTRAPSTART | INVTRAPEND | PIPE | PS | PE | SQS | SQE | DIAMOND_START | DIAMOND_STOP | TAGSTART | TAGEND | ARROW_CROSS | ARROW_POINT | ARROW_CIRCLE | ARROW_OPEN | QUOTE | SEMI;
|
||||||
%%
|
%%
|
||||||
|
@@ -231,7 +231,7 @@ describe('when parsing subgraphs', function() {
|
|||||||
expect(edges[0].type).toBe('arrow');
|
expect(edges[0].type).toBe('arrow');
|
||||||
});
|
});
|
||||||
it('should handle subgraphs with multi node statements in it', function() {
|
it('should handle subgraphs with multi node statements in it', function() {
|
||||||
const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\na b --> c e\n end;');
|
const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\na & b --> c & e\n end;');
|
||||||
|
|
||||||
const vert = flow.parser.yy.getVertices();
|
const vert = flow.parser.yy.getVertices();
|
||||||
const edges = flow.parser.yy.getEdges();
|
const edges = flow.parser.yy.getEdges();
|
||||||
|
@@ -117,7 +117,7 @@ const checkTaskDates = function(task, dateFormat, excludes) {
|
|||||||
const fixTaskDates = function(startTime, endTime, dateFormat, excludes) {
|
const fixTaskDates = function(startTime, endTime, dateFormat, excludes) {
|
||||||
let invalid = false;
|
let invalid = false;
|
||||||
let renderEndTime = null;
|
let renderEndTime = null;
|
||||||
while (startTime.date() <= endTime.date()) {
|
while (startTime <= endTime) {
|
||||||
if (!invalid) {
|
if (!invalid) {
|
||||||
renderEndTime = endTime.toDate();
|
renderEndTime = endTime.toDate();
|
||||||
}
|
}
|
||||||
@@ -502,6 +502,11 @@ const setClickFun = function(id, functionName, functionArgs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* if no arguments passed into callback, default to passing in id */
|
||||||
|
if (argList.length === 0) {
|
||||||
|
argList.push(id);
|
||||||
|
}
|
||||||
|
|
||||||
let rawTask = findTaskById(id);
|
let rawTask = findTaskById(id);
|
||||||
if (typeof rawTask !== 'undefined') {
|
if (typeof rawTask !== 'undefined') {
|
||||||
pushFun(id, () => {
|
pushFun(id, () => {
|
||||||
|
@@ -174,6 +174,26 @@ describe('when using the ganttDb', function() {
|
|||||||
expect(tasks[6].task).toEqual('test7');
|
expect(tasks[6].task).toEqual('test7');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should work when end date is the 31st', function() {
|
||||||
|
ganttDb.setDateFormat('YYYY-MM-DD');
|
||||||
|
ganttDb.addSection('Task endTime is on the 31st day of the month');
|
||||||
|
ganttDb.addTask('test1', 'id1,2019-09-30,11d');
|
||||||
|
ganttDb.addTask('test2', 'id2,after id1,20d');
|
||||||
|
const tasks = ganttDb.getTasks();
|
||||||
|
|
||||||
|
expect(tasks[0].startTime).toEqual(moment('2019-09-30', 'YYYY-MM-DD').toDate());
|
||||||
|
expect(tasks[0].endTime).toEqual(moment('2019-10-11', 'YYYY-MM-DD').toDate());
|
||||||
|
expect(tasks[1].renderEndTime).toBeNull(); // Fixed end
|
||||||
|
expect(tasks[0].id).toEqual('id1');
|
||||||
|
expect(tasks[0].task).toEqual('test1');
|
||||||
|
|
||||||
|
expect(tasks[1].startTime).toEqual(moment('2019-10-11', 'YYYY-MM-DD').toDate());
|
||||||
|
expect(tasks[1].endTime).toEqual(moment('2019-10-31', 'YYYY-MM-DD').toDate());
|
||||||
|
expect(tasks[1].renderEndTime).toBeNull(); // Fixed end
|
||||||
|
expect(tasks[1].id).toEqual('id2');
|
||||||
|
expect(tasks[1].task).toEqual('test2');
|
||||||
|
});
|
||||||
|
|
||||||
describe('when setting inclusive end dates', function() {
|
describe('when setting inclusive end dates', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
ganttDb.setDateFormat('YYYY-MM-DD');
|
ganttDb.setDateFormat('YYYY-MM-DD');
|
||||||
|
@@ -106,4 +106,34 @@ describe('when parsing a gantt diagram it', function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('should parse callback specifier with no args', function() {
|
||||||
|
spyOn(ganttDb, 'setClickEvent');
|
||||||
|
const str =
|
||||||
|
'gantt\n' +
|
||||||
|
'dateFormat YYYY-MM-DD\n' +
|
||||||
|
'section Clickable\n' +
|
||||||
|
'Visit mermaidjs :active, cl1, 2014-01-07, 3d\n' +
|
||||||
|
'Calling a callback :cl2, after cl1, 3d\n\n' +
|
||||||
|
'click cl1 href "https://mermaidjs.github.io/"\n' +
|
||||||
|
'click cl2 call ganttTestClick()\n';
|
||||||
|
|
||||||
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
|
expect(ganttDb.setClickEvent).toHaveBeenCalledWith('cl2', 'ganttTestClick', null);
|
||||||
|
});
|
||||||
|
it('should parse callback specifier with arbitrary number of args', function() {
|
||||||
|
spyOn(ganttDb, 'setClickEvent');
|
||||||
|
const str =
|
||||||
|
'gantt\n' +
|
||||||
|
'dateFormat YYYY-MM-DD\n' +
|
||||||
|
'section Clickable\n' +
|
||||||
|
'Visit mermaidjs :active, cl1, 2014-01-07, 3d\n' +
|
||||||
|
'Calling a callback :cl2, after cl1, 3d\n\n' +
|
||||||
|
'click cl1 href "https://mermaidjs.github.io/"\n' +
|
||||||
|
'click cl2 call ganttTestClick("test0", test1, test2)\n';
|
||||||
|
|
||||||
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
|
const args = '"test1", "test2", "test3"';
|
||||||
|
expect(ganttDb.setClickEvent).toHaveBeenCalledWith('cl2', 'ganttTestClick', '"test0", test1, test2');
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@@ -339,12 +339,15 @@ describe('when parsing a sequenceDiagram', function() {
|
|||||||
'participant 1 as multiline<br>text\n' +
|
'participant 1 as multiline<br>text\n' +
|
||||||
'participant 2 as multiline<br/>text\n' +
|
'participant 2 as multiline<br/>text\n' +
|
||||||
'participant 3 as multiline<br />text\n' +
|
'participant 3 as multiline<br />text\n' +
|
||||||
|
'participant 4 as multiline<br \t/>text\n' +
|
||||||
'1->>2: multiline<br>text\n' +
|
'1->>2: multiline<br>text\n' +
|
||||||
'note right of 2: multiline<br>text\n' +
|
'note right of 2: multiline<br>text\n' +
|
||||||
'2->>3: multiline<br/>text\n' +
|
'2->>3: multiline<br/>text\n' +
|
||||||
'note right of 3: multiline<br/>text\n' +
|
'note right of 3: multiline<br/>text\n' +
|
||||||
'3->>1: multiline<br />text\n' +
|
'3->>4: multiline<br />text\n' +
|
||||||
'note right of 1: multiline<br />text\n';
|
'note right of 4: multiline<br />text\n' +
|
||||||
|
'4->>1: multiline<br \t/>text\n' +
|
||||||
|
'note right of 1: multiline<br \t/>text\n';
|
||||||
|
|
||||||
parser.parse(str);
|
parser.parse(str);
|
||||||
|
|
||||||
@@ -352,6 +355,7 @@ describe('when parsing a sequenceDiagram', function() {
|
|||||||
expect(actors['1'].description).toBe('multiline<br>text');
|
expect(actors['1'].description).toBe('multiline<br>text');
|
||||||
expect(actors['2'].description).toBe('multiline<br/>text');
|
expect(actors['2'].description).toBe('multiline<br/>text');
|
||||||
expect(actors['3'].description).toBe('multiline<br />text');
|
expect(actors['3'].description).toBe('multiline<br />text');
|
||||||
|
expect(actors['4'].description).toBe('multiline<br \t/>text');
|
||||||
|
|
||||||
const messages = parser.yy.getMessages();
|
const messages = parser.yy.getMessages();
|
||||||
expect(messages[0].message).toBe('multiline<br>text');
|
expect(messages[0].message).toBe('multiline<br>text');
|
||||||
@@ -360,6 +364,8 @@ describe('when parsing a sequenceDiagram', function() {
|
|||||||
expect(messages[3].message).toBe('multiline<br/>text');
|
expect(messages[3].message).toBe('multiline<br/>text');
|
||||||
expect(messages[4].message).toBe('multiline<br />text');
|
expect(messages[4].message).toBe('multiline<br />text');
|
||||||
expect(messages[5].message).toBe('multiline<br />text');
|
expect(messages[5].message).toBe('multiline<br />text');
|
||||||
|
expect(messages[6].message).toBe('multiline<br \t/>text');
|
||||||
|
expect(messages[7].message).toBe('multiline<br \t/>text');
|
||||||
});
|
});
|
||||||
it('it should handle notes over a single actor', function() {
|
it('it should handle notes over a single actor', function() {
|
||||||
const str =
|
const str =
|
||||||
|
@@ -168,7 +168,7 @@ export const bounds = {
|
|||||||
|
|
||||||
const _drawLongText = (text, x, y, g, width) => {
|
const _drawLongText = (text, x, y, g, width) => {
|
||||||
let textHeight = 0;
|
let textHeight = 0;
|
||||||
const lines = text.split(/<br ?\/?>/gi);
|
const lines = text.split(/<br\s*\/?>/gi);
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
const textObj = svgDraw.getTextObj();
|
const textObj = svgDraw.getTextObj();
|
||||||
textObj.x = x;
|
textObj.x = x;
|
||||||
@@ -233,7 +233,7 @@ const drawMessage = function(elem, startx, stopx, verticalPos, msg, sequenceInde
|
|||||||
let textElem;
|
let textElem;
|
||||||
let counterBreaklines = 0;
|
let counterBreaklines = 0;
|
||||||
let breaklineOffset = 17;
|
let breaklineOffset = 17;
|
||||||
const breaklines = msg.message.split(/<br ?\/?>/gi);
|
const breaklines = msg.message.split(/<br\s*\/?>/gi);
|
||||||
for (const breakline of breaklines) {
|
for (const breakline of breaklines) {
|
||||||
textElem = g
|
textElem = g
|
||||||
.append('text') // text label for the x axis
|
.append('text') // text label for the x axis
|
||||||
|
@@ -18,7 +18,7 @@ export const drawRect = function(elem, rectData) {
|
|||||||
|
|
||||||
export const drawText = function(elem, textData) {
|
export const drawText = function(elem, textData) {
|
||||||
// Remove and ignore br:s
|
// Remove and ignore br:s
|
||||||
const nText = textData.text.replace(/<br ?\/?>/gi, ' ');
|
const nText = textData.text.replace(/<br\s*\/?>/gi, ' ');
|
||||||
|
|
||||||
const textElem = elem.append('text');
|
const textElem = elem.append('text');
|
||||||
textElem.attr('x', textData.x);
|
textElem.attr('x', textData.x);
|
||||||
@@ -321,7 +321,7 @@ const _drawTextCandidateFunc = (function() {
|
|||||||
function byTspan(content, g, x, y, width, height, textAttrs, conf) {
|
function byTspan(content, g, x, y, width, height, textAttrs, conf) {
|
||||||
const { actorFontSize, actorFontFamily } = conf;
|
const { actorFontSize, actorFontFamily } = conf;
|
||||||
|
|
||||||
const lines = content.split(/<br ?\/?>/gi);
|
const lines = content.split(/<br\s*\/?>/gi);
|
||||||
for (let i = 0; i < lines.length; i++) {
|
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
|
const text = g
|
||||||
|
@@ -11,7 +11,8 @@
|
|||||||
.node rect,
|
.node rect,
|
||||||
.node circle,
|
.node circle,
|
||||||
.node ellipse,
|
.node ellipse,
|
||||||
.node polygon {
|
.node polygon,
|
||||||
|
.node path {
|
||||||
fill: $mainBkg;
|
fill: $mainBkg;
|
||||||
stroke: $nodeBorder;
|
stroke: $nodeBorder;
|
||||||
stroke-width: 1px;
|
stroke-width: 1px;
|
||||||
|
Reference in New Issue
Block a user