diff --git a/cypress/integration/rendering/flowchart.spec.js b/cypress/integration/rendering/flowchart.spec.js
index 8bb4b8dff..4ea4cbcee 100644
--- a/cypress/integration/rendering/flowchart.spec.js
+++ b/cypress/integration/rendering/flowchart.spec.js
@@ -374,6 +374,7 @@ describe('Flowchart', () => {
click B testClick "click test"
classDef someclass fill:#f96;
class A someclass;
+ class C someclass;
`,
{
listUrl: false,
@@ -396,6 +397,7 @@ describe('Flowchart', () => {
{ flowchart: { htmlLabels: false } }
);
});
+
it('16: Render Stadium shape', () => {
imgSnapshotTest(
` graph TD
@@ -408,10 +410,13 @@ describe('Flowchart', () => {
click A "index.html#link-clicked" "link test"
click B testClick "click test"
classDef someclass fill:#f96;
- class A someclass;`,
+ class A someclass;
+ class C someclass;
+ `,
{ flowchart: { htmlLabels: false } }
);
});
+
it('17: Render multiline texts', () => {
imgSnapshotTest(
`graph LR
@@ -428,6 +433,7 @@ describe('Flowchart', () => {
{ flowchart: { htmlLabels: false } }
);
});
+
it('18: Chaining of nodes', () => {
imgSnapshotTest(
`graph LR
@@ -436,6 +442,7 @@ describe('Flowchart', () => {
{ flowchart: { htmlLabels: false } }
);
});
+
it('19: Multiple nodes and chaining in one statement', () => {
imgSnapshotTest(
`graph LR
@@ -444,6 +451,7 @@ describe('Flowchart', () => {
{ flowchart: { htmlLabels: false } }
);
});
+
it('20: Multiple nodes and chaining in one statement', () => {
imgSnapshotTest(
`graph TD
@@ -453,6 +461,7 @@ describe('Flowchart', () => {
{ flowchart: { htmlLabels: false } }
);
});
+
it('21: Render cylindrical shape', () => {
imgSnapshotTest(
`graph LR
@@ -474,6 +483,7 @@ describe('Flowchart', () => {
{ flowchart: { htmlLabels: false } }
);
});
+
it('22: Render a simple flowchart with nodeSpacing set to 100', () => {
imgSnapshotTest(
`graph TD
@@ -487,6 +497,7 @@ describe('Flowchart', () => {
{ flowchart: { nodeSpacing: 50 } }
);
});
+
it('23: Render a simple flowchart with rankSpacing set to 100', () => {
imgSnapshotTest(
`graph TD
@@ -500,4 +511,17 @@ describe('Flowchart', () => {
{ flowchart: { rankSpacing: '100' } }
);
});
+
+ it('24: Keep node label text (if already defined) when a style is applied', () => {
+ imgSnapshotTest(
+ `graph LR
+ A(( )) -->|step 1| B(( ))
+ B(( )) -->|step 2| C(( ))
+ C(( )) -->|step 3| D(( ))
+ linkStyle 1 stroke:greenyellow,stroke-width:2px
+ style C fill:greenyellow,stroke:green,stroke-width:4px
+ `,
+ { flowchart: { htmlLabels: false } }
+ );
+ });
});
diff --git a/cypress/integration/rendering/stateDiagram.spec.js b/cypress/integration/rendering/stateDiagram.spec.js
index 0ab68713e..3e0bf1e1c 100644
--- a/cypress/integration/rendering/stateDiagram.spec.js
+++ b/cypress/integration/rendering/stateDiagram.spec.js
@@ -121,6 +121,18 @@ describe('State diagram', () => {
{}
);
});
+ it('should handle multiline notes with different line breaks', () => {
+ imgSnapshotTest(
+ `
+ stateDiagram
+ State1
+ note right of State1
+ Line1
Line2
Line3
Line4
Line5
+ end note
+ `,
+ {}
+ );
+ });
it('should render a states with descriptions including multi-line descriptions', () => {
imgSnapshotTest(
diff --git a/dist/index.html b/dist/index.html
index 4acc24c4f..2505d8010 100644
--- a/dist/index.html
+++ b/dist/index.html
@@ -289,16 +289,17 @@ graph TB
style 456ac9b0d15a8b7f1e71073221059886 fill:#f9f,stroke:#333,stroke-width:4px
-graph TD
-A[Christmas] -->|Get money| B(Go shopping)
-B --> C{{Let me think...
Do I want something for work,
something to spend every free second with,
or something to get around?}}
-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;
+ graph TD
+ A[Christmas] -->|Get money| B(Go shopping)
+ B --> C{{Let me think...
Do I want something for work,
something to spend every free second with,
or something to get around?}}
+ 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;
+ class C someclass;
graph TD
@@ -312,6 +313,7 @@ class A someclass;
click B testClick "click test"
classDef someclass fill:#f96;
class A someclass;
+ class C someclass;
graph LR
@@ -343,6 +345,14 @@ class A someclass;
linkStyle 1 stroke:DarkGray,stroke-width:2px
linkStyle 2 stroke:DarkGray,stroke-width:2px
+
+ graph LR
+ A(( )) -->|step 1| B(( ))
+ B(( )) -->|step 2| C(( ))
+ C(( )) -->|step 3| D(( ))
+ linkStyle 1 stroke:greenyellow,stroke-width:2px
+ style C fill:greenyellow,stroke:green,stroke-width:4px
+
@@ -519,45 +529,46 @@ class Class10 {
int id
size()
}
-
+
-
- classDiagram
- Class01~T~ <|-- AveryLongClass : Cool
- <<interface>> Class01
- Class03~T~ "0" *-- "0..n" Class04
- Class05 "1" o-- "many" Class06
- Class07~T~ .. Class08
- Class09 "many" --> "1" C2 : Where am i?
- Class09 "0" --* "1..n" C3
- Class09 --|> Class07
- Class07 : equals()
- Class07 : Object[] elementData
- Class01 : #size()
- Class01 : -int chimp
- Class01 : +int gorilla
- Class08 <--> C2: Cool label
- class Class10 {
- <<service>>
- int id
- size()
- }
-
+
+ classDiagram
+ Class01~T~ <|-- AveryLongClass : Cool
+ <<interface>> Class01
+ Class03~T~ "0" *-- "0..n" Class04
+ Class05 "1" o-- "many" Class06
+ Class07~T~ .. Class08
+ Class09 "many" --> "1" C2 : Where am i?
+ Class09 "0" --* "1..n" C3
+ Class09 --|> Class07
+ Class07 : equals()
+ Class07 : Object[] elementData
+ Class01 : #size()
+ Class01 : -int chimp
+ Class01 : +int gorilla
+ Class08 <--> C2: Cool label
+ class Class10 {
+ <<service>>
+ int id
+ size()
+ }
+
stateDiagram
State1
-
+
-
-
- stateDiagram
- [*] --> First
- state First {
- [*] --> second
- second --> [*]
- }
-
+
+
+
+ stateDiagram
+ [*] --> First
+ state First {
+ [*] --> second
+ second --> [*]
+ }
+
stateDiagram
State1: The state with a note
@@ -567,8 +578,14 @@ class Class10 {
end note
State1 --> State2
note left of State2 : This is the note to the left.
-
-
+
+
+ stateDiagram
+ State1
+ note right of State1
+ Line1
Line2
Line3
Line4
Line5
+ end note
+
-
+</script>
-A summary of all options and their defaults is found [here](https://github.com/knsv/mermaid/blob/master/docs/mermaidAPI.md#mermaidapi-configuration-defaults). A description of each option follows below.
+
+A summary of all options and their defaults is found [here][2]. A description of each option follows below.
## theme
@@ -333,3 +333,5 @@ mermaidAPI.initialize({
[1]: https://github.com/knsv/mermaid/blob/master/docs/mermaidAPI.md#render
+
+[2]: https://github.com/knsv/mermaid/blob/master/docs/mermaidAPI.md#mermaidapi-configuration-defaults
diff --git a/package.json b/package.json
index cb3f2461b..66310f158 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "mermaid",
- "version": "8.4.5",
+ "version": "8.4.6",
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
"main": "dist/mermaid.core.js",
"keywords": [
diff --git a/src/diagrams/class/classDb.js b/src/diagrams/class/classDb.js
index a20bdd075..dcb62164c 100644
--- a/src/diagrams/class/classDb.js
+++ b/src/diagrams/class/classDb.js
@@ -140,7 +140,7 @@ export const addMembers = function(className, members) {
export const cleanupLabel = function(label) {
if (label.substring(0, 1) === ':') {
- return label.substr(2).trim();
+ return label.substr(1).trim();
} else {
return label.trim();
}
diff --git a/src/diagrams/class/classDiagram.spec.js b/src/diagrams/class/classDiagram.spec.js
index 8510b086d..4ac53ae10 100644
--- a/src/diagrams/class/classDiagram.spec.js
+++ b/src/diagrams/class/classDiagram.spec.js
@@ -67,6 +67,48 @@ describe('class diagram, ', function () {
parser.parse(str);
});
+ it('should break when another `{`is encountered before closing the first one while defining generic class with brackets', function() {
+ const str =
+ 'classDiagram\n' +
+ 'class Dummy_Class~T~ {\n' +
+ 'String data\n' +
+ ' void methods()\n' +
+ '}\n' +
+ '\n' +
+ 'class Dummy_Class {\n' +
+ 'class Flight {\n' +
+ ' flightNumber : Integer\n' +
+ ' departureTime : Date\n' +
+ '}';
+ let testPased =false;
+ try{
+ parser.parse(str);
+ }catch (error){
+ console.log(error.name);
+ testPased = true;
+ }
+ expect(testPased).toBe(true);
+ });
+
+ it('should break when EOF is encountered before closing the first `{` while defining generic class with brackets', function() {
+ const str =
+ 'classDiagram\n' +
+ 'class Dummy_Class~T~ {\n' +
+ 'String data\n' +
+ ' void methods()\n' +
+ '}\n' +
+ '\n' +
+ 'class Dummy_Class {\n';
+ let testPased =false;
+ try{
+ parser.parse(str);
+ }catch (error){
+ console.log(error.name);
+ testPased = true;
+ }
+ expect(testPased).toBe(true);
+ });
+
it('should handle generic class with brackets', function() {
const str =
'classDiagram\n' +
@@ -79,8 +121,6 @@ describe('class diagram, ', function () {
' flightNumber : Integer\n' +
' departureTime : Date\n' +
'}';
-
- parser.parse(str);
});
it('should handle class definitions', function() {
diff --git a/src/diagrams/class/classRenderer.js b/src/diagrams/class/classRenderer.js
index 39a15a5bd..5e6208ac5 100644
--- a/src/diagrams/class/classRenderer.js
+++ b/src/diagrams/class/classRenderer.js
@@ -540,9 +540,14 @@ export const draw = function(text, id) {
logger.info(
'tjoho' + getGraphId(relation.id1) + getGraphId(relation.id2) + JSON.stringify(relation)
);
- g.setEdge(getGraphId(relation.id1), getGraphId(relation.id2), {
- relation: relation
- });
+ g.setEdge(
+ getGraphId(relation.id1),
+ getGraphId(relation.id2),
+ {
+ relation: relation
+ },
+ relation.title || 'DEFAULT'
+ );
});
dagre.layout(g);
g.nodes().forEach(function(v) {
diff --git a/src/diagrams/class/parser/classDiagram.jison b/src/diagrams/class/parser/classDiagram.jison
index 7bd768138..12e9a2564 100644
--- a/src/diagrams/class/parser/classDiagram.jison
+++ b/src/diagrams/class/parser/classDiagram.jison
@@ -14,6 +14,8 @@
\s+ /* skip whitespace */
"classDiagram" return 'CLASS_DIAGRAM';
[\{] { this.begin("struct"); /*console.log('Starting struct');*/return 'STRUCT_START';}
+<> return "EOF_IN_STRUCT";
+[\{] return "OPEN_IN_STRUCT";
\} { /*console.log('Ending struct');*/this.popState(); return 'STRUCT_STOP';}}
[\n] /* nothing */
[^\{\}\n]* { /*console.log('lex-member: ' + yytext);*/ return "MEMBER";}
diff --git a/src/diagrams/flowchart/flowDb.js b/src/diagrams/flowchart/flowDb.js
index 4b78231c2..33c85a15d 100644
--- a/src/diagrams/flowchart/flowDb.js
+++ b/src/diagrams/flowchart/flowDb.js
@@ -52,7 +52,7 @@ export const addVertex = function(_id, text, type, style, classes) {
vertices[id].text = txt;
} else {
- if (!vertices[id].text) {
+ if (typeof vertices[id].text === 'undefined') {
vertices[id].text = _id;
}
}
diff --git a/src/diagrams/flowchart/flowRenderer.js b/src/diagrams/flowchart/flowRenderer.js
index 52031e5db..931608b45 100644
--- a/src/diagrams/flowchart/flowRenderer.js
+++ b/src/diagrams/flowchart/flowRenderer.js
@@ -88,7 +88,7 @@ export const addVertices = function(vert, g, svgId) {
} else {
const svgLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text');
- const rows = vertexText.split(/
/);
+ const rows = vertexText.split(/
/gi);
for (let j = 0; j < rows.length; j++) {
const tspan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
@@ -237,7 +237,7 @@ export const addEdges = function(edges, g) {
edgeData.label = '' + edge.text + '';
} else {
edgeData.labelType = 'text';
- edgeData.label = edge.text.replace(/
/g, '\n');
+ edgeData.label = edge.text.replace(/
/gi, '\n');
if (typeof edge.style === 'undefined') {
edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none';
@@ -461,6 +461,7 @@ export const draw = function(text, id) {
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', 'class', vertex.classes.join(' '));
link.setAttributeNS('http://www.w3.org/2000/svg', 'href', vertex.link);
link.setAttributeNS('http://www.w3.org/2000/svg', 'rel', 'noopener');
diff --git a/src/diagrams/flowchart/flowRenderer.spec.js b/src/diagrams/flowchart/flowRenderer.spec.js
index de8a6a485..d691840ed 100644
--- a/src/diagrams/flowchart/flowRenderer.spec.js
+++ b/src/diagrams/flowchart/flowRenderer.spec.js
@@ -55,6 +55,43 @@ describe('the flowchart renderer', function() {
expect(addedNodes[0][1]).toHaveProperty('ry', expectedRadios);
});
});
+
+ [
+ 'Multi
Line',
+ 'Multi
Line',
+ 'Multi
Line',
+ 'Multi
Line'
+ ].forEach(function(labelText) {
+ it('should handle multiline texts with different line breaks', function() {
+ const addedNodes = [];
+ const mockG = {
+ setNode: function(id, object) {
+ addedNodes.push([id, object]);
+ }
+ };
+ addVertices(
+ {
+ v1: {
+ type: 'rect',
+ id: 'my-node-id',
+ classes: [],
+ styles: [],
+ text: 'Multi
Line'
+ }
+ },
+ mockG,
+ 'svg-id'
+ );
+ expect(addedNodes).toHaveLength(1);
+ expect(addedNodes[0][0]).toEqual('my-node-id');
+ expect(addedNodes[0][1]).toHaveProperty('id', 'my-node-id');
+ expect(addedNodes[0][1]).toHaveProperty('labelType', 'svg');
+ expect(addedNodes[0][1].label).toBeDefined();
+ expect(addedNodes[0][1].label).toBeDefined(); // node
+ expect(addedNodes[0][1].label.firstChild.innerHTML).toEqual('Multi'); // node, line 1
+ expect(addedNodes[0][1].label.lastChild.innerHTML).toEqual('Line'); // node, line 2
+ });
+ });
});
[
@@ -109,9 +146,11 @@ describe('the flowchart renderer', function() {
{ text: 'Multi
Line' },
{ text: 'Multi
Line' },
{ text: 'Multi
Line' },
+ { text: 'Multi
Line' },
{ style: ['stroke:DarkGray', 'stroke-width:2px'], text: 'Multi
Line' },
{ style: ['stroke:DarkGray', 'stroke-width:2px'], text: 'Multi
Line' },
- { style: ['stroke:DarkGray', 'stroke-width:2px'], text: 'Multi
Line' }
+ { style: ['stroke:DarkGray', 'stroke-width:2px'], text: 'Multi
Line' },
+ { style: ['stroke:DarkGray', 'stroke-width:2px'], text: 'Multi
Line' }
],
mockG,
'svg-id'
diff --git a/src/diagrams/flowchart/parser/flow-style.spec.js b/src/diagrams/flowchart/parser/flow-style.spec.js
index b9d678b54..db92660ae 100644
--- a/src/diagrams/flowchart/parser/flow-style.spec.js
+++ b/src/diagrams/flowchart/parser/flow-style.spec.js
@@ -86,6 +86,17 @@ describe('[Style] when parsing', () => {
expect(vert['T'].styles[1]).toBe('border:1px solid red');
});
+ it('should keep node label text (if already defined) when a style is applied', function() {
+ const res = flow.parser.parse('graph TD;A(( ));B((Test));C;style A background:#fff;style D border:1px solid red;');
+
+ const vert = flow.parser.yy.getVertices();
+
+ expect(vert['A'].text).toBe('');
+ expect(vert['B'].text).toBe('Test');
+ expect(vert['C'].text).toBe('C');
+ expect(vert['D'].text).toBe('D');
+ });
+
it('should be possible to declare a class', function() {
const res = flow.parser.parse(
'graph TD;classDef exClass background:#bbb,border:1px solid red;'
diff --git a/src/diagrams/sequence/sequenceDb.js b/src/diagrams/sequence/sequenceDb.js
index 050691a6c..cb873147e 100644
--- a/src/diagrams/sequence/sequenceDb.js
+++ b/src/diagrams/sequence/sequenceDb.js
@@ -16,6 +16,25 @@ export const addActor = function(id, name, description) {
actors[id] = { name: name, description: description };
};
+const activationCount = part => {
+ let i = 0;
+ let count = 0;
+ for (i = 0; i < messages.length; i++) {
+ // console.warn(i, messages[i]);
+ if (messages[i].type === LINETYPE.ACTIVE_START) {
+ if (messages[i].from.actor === part) {
+ count++;
+ }
+ }
+ if (messages[i].type === LINETYPE.ACTIVE_END) {
+ if (messages[i].from.actor === part) {
+ count--;
+ }
+ }
+ }
+ return count;
+};
+
export const addMessage = function(idFrom, idTo, message, answer) {
messages.push({ from: idFrom, to: idTo, message: message, answer: answer });
};
@@ -24,7 +43,25 @@ export const addSignal = function(idFrom, idTo, message, messageType) {
logger.debug(
'Adding message from=' + idFrom + ' to=' + idTo + ' message=' + message + ' type=' + messageType
);
+
+ if (messageType === LINETYPE.ACTIVE_END) {
+ const cnt = activationCount(idFrom.actor);
+ logger.debug('Adding message from=', messages, cnt);
+ if (cnt < 1) {
+ // Bail out as there is an activation signal from an inactive participant
+ var error = new Error('Trying to inactivate an inactive participant (' + idFrom.actor + ')');
+ error.hash = {
+ text: '->>-',
+ token: '->>-',
+ line: '1',
+ loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
+ expected: ["'ACTIVE_PARTICIPANT'"]
+ };
+ throw error;
+ }
+ }
messages.push({ from: idFrom, to: idTo, message: message, type: messageType });
+ return true;
};
export const getMessages = function() {
diff --git a/src/diagrams/sequence/sequenceDiagram.spec.js b/src/diagrams/sequence/sequenceDiagram.spec.js
index 2f1832865..5b32c4627 100644
--- a/src/diagrams/sequence/sequenceDiagram.spec.js
+++ b/src/diagrams/sequence/sequenceDiagram.spec.js
@@ -214,6 +214,33 @@ describe('when parsing a sequenceDiagram', function() {
expect(messages[7].type).toBe(parser.yy.LINETYPE.ACTIVE_END);
expect(messages[7].from.actor).toBe('Carol');
});
+ it('it should handle fail parsing when activating an inactive participant', function() {
+ const str =
+ `sequenceDiagram
+ participant user as End User
+ participant Server as Server
+ participant System as System
+ participant System2 as System2
+
+ user->>+Server: Test
+ user->>+Server: Test2
+ user->>System: Test
+ Server->>-user: Test
+ Server->>-user: Test2
+
+ %% The following deactivation of Server will fail
+ Server->>-user: Test3`;
+
+ let error = false;
+ try {
+ parser.parse(str);
+ } catch(e) {
+ console.log(e.hash);
+ error = true;
+ }
+ expect(error).toBe(true);
+ });
+
it('it should handle comments in a sequenceDiagram', function() {
const str =
'sequenceDiagram\n' +
diff --git a/src/diagrams/state/shapes.js b/src/diagrams/state/shapes.js
index f4711d493..d42228e41 100644
--- a/src/diagrams/state/shapes.js
+++ b/src/diagrams/state/shapes.js
@@ -280,7 +280,7 @@ const drawForkJoinState = (g, stateDef) => {
export const drawText = function(elem, textData) {
// Remove and ignore br:s
- const nText = textData.text.replace(/
/gi, ' ');
+ const nText = textData.text.replace(/
/gi, ' ');
const textElem = elem.append('text');
textElem.attr('x', textData.x);
@@ -308,7 +308,7 @@ const _drawLongText = (_text, x, y, g) => {
let text = _text.replace(/\r\n/g, '
');
text = text.replace(/\n/g, '
');
- const lines = text.split(/
/gi);
+ const lines = text.split(/
/gi);
let tHeight = 1.25 * getConfig().state.noteMargin;
for (const line of lines) {
@@ -392,7 +392,7 @@ export const drawState = function(elem, stateDef) {
};
const getRows = s => {
- let str = s.replace(/
/gi, '#br#');
+ let str = s.replace(/
/gi, '#br#');
str = str.replace(/\\n/g, '#br#');
return str.split('#br#');
};
diff --git a/src/diagrams/state/stateDiagram.spec.js b/src/diagrams/state/stateDiagram.spec.js
index ee3152682..d609978ad 100644
--- a/src/diagrams/state/stateDiagram.spec.js
+++ b/src/diagrams/state/stateDiagram.spec.js
@@ -261,6 +261,16 @@ describe('state diagram, ', function() {
parser.parse(str);
});
+ it('should handle multiline notes with different line breaks', function() {
+ const str = `stateDiagram
+ State1
+ note right of State1
+ Line1
Line2
Line3
Line4
Line5
+ end note
+ `;
+
+ parser.parse(str);
+ });
it('should handle floating notes', function() {
const str = `stateDiagram
foo: bar
diff --git a/src/diagrams/state/stateRenderer.js b/src/diagrams/state/stateRenderer.js
index 4b152fe84..cec09a898 100644
--- a/src/diagrams/state/stateRenderer.js
+++ b/src/diagrams/state/stateRenderer.js
@@ -102,7 +102,7 @@ const getLabelWidth = text => {
/* TODO: REMOVE DUPLICATION, SEE SHAPES */
const getRows = s => {
if (!s) return 1;
- let str = s.replace(/
/gi, '#br#');
+ let str = s.replace(/
/gi, '#br#');
str = str.replace(/\\n/g, '#br#');
return str.split('#br#');
};
diff --git a/src/mermaid.js b/src/mermaid.js
index 08bf9af19..0cf24e81f 100644
--- a/src/mermaid.js
+++ b/src/mermaid.js
@@ -98,7 +98,7 @@ const init = function() {
txt = he
.decode(txt)
.trim()
- .replace(/
/gi, '
');
+ .replace(/
/gi, '
');
mermaidAPI.render(
id,
diff --git a/src/mermaidAPI.js b/src/mermaidAPI.js
index 975b38299..08c090261 100644
--- a/src/mermaidAPI.js
+++ b/src/mermaidAPI.js
@@ -52,14 +52,14 @@ for (const themeName of ['default', 'forest', 'dark', 'neutral']) {
*
* mermaid.initialize({
* flowchart:{
- * htmlLabels: false
+ * htmlLabels: false
* }
* });
*
*
* **Example 2:**
*
- *
+ * </script>
*
* A summary of all options and their defaults is found [here](https://github.com/knsv/mermaid/blob/master/docs/mermaidAPI.md#mermaidapi-configuration-defaults). A description of each option follows below.
*
@@ -142,6 +142,20 @@ const config = {
*/
htmlLabels: true,
+ /**
+ * Defines the spacing between nodes on the same level (meaning horizontal spacing for
+ * TB or BT graphs, and the vertical spacing for LR as well as RL graphs).
+ * **Default value 50**.
+ */
+ nodeSpacing: 50,
+
+ /**
+ * Defines the spacing between nodes on different levels (meaning vertical spacing for
+ * TB or BT graphs, and the horizontal spacing for LR as well as RL graphs).
+ * **Default value 50**.
+ */
+ rankSpacing: 50,
+
/**
* How mermaid renders curves for flowcharts. Possible values are
* * basis
diff --git a/src/utils.js b/src/utils.js
index 1e17366d1..de7718773 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -84,8 +84,7 @@ export const sanitize = (text, config) => {
htmlLabels = false;
if (config.securityLevel !== 'loose' && htmlLabels) { // eslint-disable-line
- txt = txt.replace(/
/g, '#br#');
- txt = txt.replace(/
/g, '#br#');
+ txt = txt.replace(/
/gi, '#br#');
txt = txt.replace(//g, '>');
txt = txt.replace(/=/g, '=');
txt = txt.replace(/#br#/g, '
');