From c6191b19f979ff7876eada8d95a43e02ecb15eaa Mon Sep 17 00:00:00 2001 From: Andreas Stopat Date: Sun, 2 Jun 2024 21:44:41 +0200 Subject: [PATCH] feat: change direction of erDiagram Resolves #3851 --- .../integration/rendering/erDiagram.spec.js | 48 +++++++++++++++++++ demos/er.html | 13 ++--- packages/mermaid/src/diagrams/er/erDb.js | 8 ++++ .../mermaid/src/diagrams/er/erRenderer.js | 2 +- .../src/diagrams/er/parser/erDiagram.jison | 18 +++++++ .../src/diagrams/er/parser/erDiagram.spec.js | 9 ++++ .../docs/syntax/entityRelationshipDiagram.md | 25 ++++++++++ 7 files changed, 116 insertions(+), 7 deletions(-) diff --git a/cypress/integration/rendering/erDiagram.spec.js b/cypress/integration/rendering/erDiagram.spec.js index 578f5a3984..5584c97ddd 100644 --- a/cypress/integration/rendering/erDiagram.spec.js +++ b/cypress/integration/rendering/erDiagram.spec.js @@ -322,4 +322,52 @@ ORDER ||--|{ LINE-ITEM : contains { logLevel: 1 } ); }); + + it('should handle the direction statement with TB', () => { + imgSnapshotTest( + ` + erDiagram + direction TB + CUSTOMER ||--o{ ORDER : places + ORDER ||--|{ LINE-ITEM : contains + `, + { logLevel: 1 } + ); + }); + + it('should handle the direction statement with BT', () => { + imgSnapshotTest( + ` + erDiagram + direction BT + CUSTOMER ||--o{ ORDER : places + ORDER ||--|{ LINE-ITEM : contains + `, + { logLevel: 1 } + ); + }); + + it('should handle the direction statement with LR', () => { + imgSnapshotTest( + ` + erDiagram + direction LR + CUSTOMER ||--o{ ORDER : places + ORDER ||--|{ LINE-ITEM : contains + `, + { logLevel: 1 } + ); + }); + + it('should handle the direction statement with RL', () => { + imgSnapshotTest( + ` + erDiagram + direction RL + CUSTOMER ||--o{ ORDER : places + ORDER ||--|{ LINE-ITEM : contains + `, + { logLevel: 1 } + ); + }); }); diff --git a/demos/er.html b/demos/er.html index 0b4b82bacf..aa83f2e922 100644 --- a/demos/er.html +++ b/demos/er.html @@ -114,6 +114,7 @@
     erDiagram
+      direction LR
       p[Person] {
           string firstName
           string lastName
@@ -130,12 +131,12 @@
       _customer_order {
           bigint id PK
           bigint customer_id FK
-          text shipping_address 
-          text delivery_method 
-          timestamp_with_time_zone ordered_at 
-          numeric total_tax_amount 
-          numeric total_price 
-          text payment_method 
+          text shipping_address
+          text delivery_method
+          timestamp_with_time_zone ordered_at
+          numeric total_tax_amount
+          numeric total_price
+          text payment_method
       }
     

diff --git a/packages/mermaid/src/diagrams/er/erDb.js b/packages/mermaid/src/diagrams/er/erDb.js index 745ef938ad..c408cbbb69 100644 --- a/packages/mermaid/src/diagrams/er/erDb.js +++ b/packages/mermaid/src/diagrams/er/erDb.js @@ -80,6 +80,12 @@ const clear = function () { commonClear(); }; +let direction = 'TB'; +const getDirection = () => direction; +const setDirection = (dir) => { + direction = dir; +}; + export default { Cardinality, Identification, @@ -96,4 +102,6 @@ export default { getAccDescription, setDiagramTitle, getDiagramTitle, + setDirection, + getDirection }; diff --git a/packages/mermaid/src/diagrams/er/erRenderer.js b/packages/mermaid/src/diagrams/er/erRenderer.js index 33fb5bd4ae..f94f1d3250 100644 --- a/packages/mermaid/src/diagrams/er/erRenderer.js +++ b/packages/mermaid/src/diagrams/er/erRenderer.js @@ -601,7 +601,7 @@ export const draw = function (text, id, _version, diagObj) { compound: false, }) .setGraph({ - rankdir: conf.layoutDirection, + rankdir: diagObj.db.getDirection(), marginx: 20, marginy: 20, nodesep: 100, diff --git a/packages/mermaid/src/diagrams/er/parser/erDiagram.jison b/packages/mermaid/src/diagrams/er/parser/erDiagram.jison index 135efc7846..429abf8db5 100644 --- a/packages/mermaid/src/diagrams/er/parser/erDiagram.jison +++ b/packages/mermaid/src/diagrams/er/parser/erDiagram.jison @@ -7,6 +7,12 @@ %x acc_descr_multiline %% +.*direction\s+TB[^\n]* return 'direction_tb'; +.*direction\s+BT[^\n]* return 'direction_bt'; +.*direction\s+RL[^\n]* return 'direction_rl'; +.*direction\s+LR[^\n]* return 'direction_lr'; +\%\%(?!\{)*[^\n]*(\r?\n?)+ /* skip comments */ +\%\%[^\n]*(\r?\n)* /* skip comments */ accTitle\s*":"\s* { this.begin("acc_title");return 'acc_title'; } (?!\n|;|#)*[^\n]* { this.popState(); return "acc_title_value"; } accDescr\s*":"\s* { this.begin("acc_descr");return 'acc_descr'; } @@ -109,6 +115,7 @@ statement | entityName SQS entityName SQE BLOCK_START BLOCK_STOP { yy.addEntity($1, $3); } | entityName SQS entityName SQE { yy.addEntity($1, $3); } | title title_value { $$=$2.trim();yy.setAccTitle($$); } + | direction | acc_title acc_title_value { $$=$2.trim();yy.setAccTitle($$); } | acc_descr acc_descr_value { $$=$2.trim();yy.setAccDescription($$); } | acc_descr_multiline_value { $$=$1.trim();yy.setAccDescription($$); } @@ -180,4 +187,15 @@ role | 'ALPHANUM' { $$ = $1; } ; +direction + : direction_tb + { yy.setDirection('TB');} + | direction_bt + { yy.setDirection('BT');} + | direction_rl + { yy.setDirection('RL');} + | direction_lr + { yy.setDirection('LR');} + ; + %% diff --git a/packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js b/packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js index e36454f313..dc797a4a6d 100644 --- a/packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js +++ b/packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js @@ -803,4 +803,13 @@ describe('when parsing ER diagram it...', function () { } ); }); + + it('should have the default direction TB', function () { + erDiagram.parser.parse('erDiagram\nA ||--|{ B : has'); + expect(erDb.getDirection()).toBe('TB'); + }); + + it('should handle the direction statement', function () { + erDiagram.parser.parse('erDiagram\ndirection LR\nA ||--|{ B : has'); + }); }); diff --git a/packages/mermaid/src/docs/syntax/entityRelationshipDiagram.md b/packages/mermaid/src/docs/syntax/entityRelationshipDiagram.md index ca7cb79c35..b309d139ec 100644 --- a/packages/mermaid/src/docs/syntax/entityRelationshipDiagram.md +++ b/packages/mermaid/src/docs/syntax/entityRelationshipDiagram.md @@ -188,6 +188,31 @@ erDiagram MANUFACTURER only one to zero or more CAR : makes ``` +## Setting the direction of the diagram + +With entity relationship diagrams you can use the direction statement to set the direction in which the diagram will render: + +```mermaid-example +erDiagram + direction LR + CUSTOMER ||--o{ ORDER : places + CUSTOMER { + string name + string custNumber + string sector + } + ORDER ||--|{ LINE-ITEM : contains + ORDER { + int orderNumber + string deliveryAddress + } + LINE-ITEM { + string productCode + int quantity + float pricePerUnit + } +``` + ### Other Things - If you want the relationship label to be more than one word, you must use double quotes around the phrase