From 7257bba3f3c4e7747e5895b054a689f377be4538 Mon Sep 17 00:00:00 2001 From: may4everL Date: Tue, 9 Aug 2022 22:44:11 -0700 Subject: [PATCH 01/20] Added lollipop feature for updated codebase --- demos/index.html | 25 ++++++++++++++++++++ src/dagre-wrapper/edges.js | 6 +++++ src/dagre-wrapper/markers.js | 19 +++++++++++++++ src/diagrams/class/classDb.js | 1 + src/diagrams/class/classRenderer-v2.js | 11 ++++++++- src/diagrams/class/parser/classDiagram.jison | 3 +++ src/diagrams/class/styles.js | 12 ++++++++++ src/diagrams/class/svgDraw.js | 2 ++ 8 files changed, 78 insertions(+), 1 deletion(-) diff --git a/demos/index.html b/demos/index.html index f96d2f2af..904fde7df 100644 --- a/demos/index.html +++ b/demos/index.html @@ -879,6 +879,31 @@ Enterprise_Boundary(b0, "BankBoundary0") { } +
+ classDiagram + Interface1 ()-- Interface1Impl +
+ +
+ classDiagram + direction LR + Animal ()-- Dog + Dog : bark() + Dog : species() +
+ +
+ classDiagram + direction RL + Fruit ()-- Apple + Apple : color() + Apple : -int leafCount() + Fruit ()-- Pineapple + Pineapple : color() + Pineapple : -int leafCount() + Pineapple : -int spikeCount() +
+
stateDiagram accDescription This is a state diagram showing one state diff --git a/src/dagre-wrapper/edges.js b/src/dagre-wrapper/edges.js index 60ded826e..677fda9f1 100644 --- a/src/dagre-wrapper/edges.js +++ b/src/dagre-wrapper/edges.js @@ -510,6 +510,9 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph case 'dependency': svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-dependencyStart' + ')'); break; + case 'lollipop': + svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-lollipopStart' + ')'); + break; default: } switch (edge.arrowTypeEnd) { @@ -537,6 +540,9 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph case 'dependency': svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-dependencyEnd' + ')'); break; + case 'lollipop': + svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-lollipopEnd' + ')'); + break; default: } let paths = {}; diff --git a/src/dagre-wrapper/markers.js b/src/dagre-wrapper/markers.js index ca2a12200..b28be4119 100644 --- a/src/dagre-wrapper/markers.js +++ b/src/dagre-wrapper/markers.js @@ -119,6 +119,24 @@ const dependency = (elem, type) => { .append('path') .attr('d', 'M 18,7 L9,13 L14,7 L9,1 Z'); }; +const lollipop = (elem, type, id) => { + elem + .append('defs') + .append('marker') + .attr('id', type + '-lollipopStart') + .attr('class', 'marker lollipop ' + type) + .attr('refX', 0) + .attr('refY', 7) + .attr('markerWidth', 190) + .attr('markerHeight', 240) + .attr('orient', 'auto') + .append('circle') + .attr('stroke', 'black') + .attr('fill', 'white') + .attr('cx', 6) + .attr('cy', 7) + .attr('r', 6); +}; const point = (elem, type) => { elem .append('marker') @@ -250,6 +268,7 @@ const markers = { composition, aggregation, dependency, + lollipop, point, circle, cross, diff --git a/src/diagrams/class/classDb.js b/src/diagrams/class/classDb.js index 9f6ccde63..690849fa8 100644 --- a/src/diagrams/class/classDb.js +++ b/src/diagrams/class/classDb.js @@ -311,6 +311,7 @@ export const relationType = { EXTENSION: 1, COMPOSITION: 2, DEPENDENCY: 3, + LOLLIPOP: 4, }; const setupToolTips = function (element) { diff --git a/src/diagrams/class/classRenderer-v2.js b/src/diagrams/class/classRenderer-v2.js index d82365587..11c2a6dc5 100644 --- a/src/diagrams/class/classRenderer-v2.js +++ b/src/diagrams/class/classRenderer-v2.js @@ -338,7 +338,13 @@ export const draw = function (text, id, _version, diagObj) { // Run the renderer. This is what draws the final graph. const element = root.select('#' + id + ' g'); - render(element, g, ['aggregation', 'extension', 'composition', 'dependency'], 'classDiagram', id); + render( + element, + g, + ['aggregation', 'extension', 'composition', 'dependency', 'lollipop'], + 'classDiagram', + id + ); setupGraphViewbox(g, svg, conf.diagramPadding, conf.useMaxWidth); @@ -420,6 +426,9 @@ function getArrowMarker(type) { case 3: marker = 'dependency'; break; + case 4: + marker = 'lollipop'; + break; default: marker = 'none'; } diff --git a/src/diagrams/class/parser/classDiagram.jison b/src/diagrams/class/parser/classDiagram.jison index f6e603a3d..ba0e69fba 100644 --- a/src/diagrams/class/parser/classDiagram.jison +++ b/src/diagrams/class/parser/classDiagram.jison @@ -44,6 +44,7 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili "classDiagram-v2" return 'CLASS_DIAGRAM'; "classDiagram" return 'CLASS_DIAGRAM'; [{] { this.begin("struct"); /*console.log('Starting struct');*/ return 'STRUCT_START';} +"[*]" { /*console.log('EDGE_STATE=',yytext);*/ return 'EDGE_STATE';} <> return "EOF_IN_STRUCT"; [{] return "OPEN_IN_STRUCT"; [}] { /*console.log('Ending struct');*/this.popState(); return 'STRUCT_STOP';}} @@ -104,6 +105,7 @@ Function arguments are optional: 'call ()' simply executes 'callb \s*\< return 'DEPENDENCY'; \s*\* return 'COMPOSITION'; \s*o return 'AGGREGATION'; +\s*\(\) return 'LOLLIPOP'; \-\- return 'LINE'; \.\. return 'DOTTED_LINE'; ":"{1}[^:\n;]+ return 'LABEL'; @@ -310,6 +312,7 @@ relationType | EXTENSION { $$=yy.relationType.EXTENSION;} | COMPOSITION { $$=yy.relationType.COMPOSITION;} | DEPENDENCY { $$=yy.relationType.DEPENDENCY;} + | LOLLIPOP { $$=yy.relationType.LOLLIPOP;} ; lineType diff --git a/src/diagrams/class/styles.js b/src/diagrams/class/styles.js index 31b82cf56..9e7665c58 100644 --- a/src/diagrams/class/styles.js +++ b/src/diagrams/class/styles.js @@ -128,6 +128,18 @@ g.classGroup line { stroke-width: 1; } +#lollipopStart, .lollipop { + fill: ${options.mainBkg} !important; + stroke: ${options.lineColor} !important; + stroke-width: 1; +} + +#lollipopEnd, .lollipop { + fill: ${options.mainBkg} !important; + stroke: ${options.lineColor} !important; + stroke-width: 1; +} + .edgeTerminals { font-size: 11px; } diff --git a/src/diagrams/class/svgDraw.js b/src/diagrams/class/svgDraw.js index a6b11cd95..a3daf2a86 100644 --- a/src/diagrams/class/svgDraw.js +++ b/src/diagrams/class/svgDraw.js @@ -14,6 +14,8 @@ export const drawEdge = function (elem, path, relation, conf, diagObj) { return 'composition'; case diagObj.db.DEPENDENCY: return 'dependency'; + case diagObj.db.LOLLIPOP: + return 'lollipop'; } }; From a3ace00ed4e830506dae30953cd76e2cf534f43b Mon Sep 17 00:00:00 2001 From: Fabien Savy Date: Wed, 24 Aug 2022 17:07:56 +0200 Subject: [PATCH 02/20] Fix font weight for messages in sequence diagrams --- src/diagrams/sequence/styles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diagrams/sequence/styles.js b/src/diagrams/sequence/styles.js index 1d99ebc97..5c36b4ed1 100644 --- a/src/diagrams/sequence/styles.js +++ b/src/diagrams/sequence/styles.js @@ -45,7 +45,7 @@ const getStyles = (options) => .messageText { fill: ${options.signalTextColor}; - stroke: ${options.signalTextColor}; + stroke: none; } .labelBox { From 0583c4fa25a1e04674b8e619b31d54c0a6a5d8fa Mon Sep 17 00:00:00 2001 From: Valentin Valls Date: Wed, 24 Aug 2022 22:26:39 +0200 Subject: [PATCH 03/20] Added 'ms' duration --- cypress/integration/rendering/gantt.spec.js | 18 ++++++++++++++++++ src/diagrams/gantt/ganttDb.js | 5 ++++- src/diagrams/gantt/ganttDb.spec.js | 21 +++++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/cypress/integration/rendering/gantt.spec.js b/cypress/integration/rendering/gantt.spec.js index a94132942..7dc7c6cf5 100644 --- a/cypress/integration/rendering/gantt.spec.js +++ b/cypress/integration/rendering/gantt.spec.js @@ -163,6 +163,24 @@ describe('Gantt diagram', () => { ); }); + it('should handle milliseconds', () => { + imgSnapshotTest( + ` + gantt + title A Gantt Diagram + dateFormat x + axisFormat %L + section Section + A task :a1, 0, 30ms + Another task :after a1, 20ms + section Another + Another another task :b1, 20, 12ms + Another another another task :after b1, 24ms + `, + {} + ); + }); + it('should render a gantt diagram when useMaxWidth is true (default)', () => { renderGraph( ` diff --git a/src/diagrams/gantt/ganttDb.js b/src/diagrams/gantt/ganttDb.js index 6014cd9bb..b69d46518 100644 --- a/src/diagrams/gantt/ganttDb.js +++ b/src/diagrams/gantt/ganttDb.js @@ -233,6 +233,9 @@ const getStartDate = function (prevTime, dateFormat, str) { const durationToDate = function (durationStatement, relativeTime) { if (durationStatement !== null) { switch (durationStatement[2]) { + case 'ms': + relativeTime.add(durationStatement[1], 'milliseconds'); + break; case 's': relativeTime.add(durationStatement[1], 'seconds'); break; @@ -267,7 +270,7 @@ const getEndDate = function (prevTime, dateFormat, str, inclusive) { return mDate.toDate(); } - return durationToDate(/^([\d]+)([wdhms])/.exec(str.trim()), moment(prevTime)); + return durationToDate(/^([\d]+)([wdhms]|ms)$/.exec(str.trim()), moment(prevTime)); }; let taskCnt = 0; diff --git a/src/diagrams/gantt/ganttDb.spec.js b/src/diagrams/gantt/ganttDb.spec.js index 406a4d070..d07aee4bf 100644 --- a/src/diagrams/gantt/ganttDb.spec.js +++ b/src/diagrams/gantt/ganttDb.spec.js @@ -99,6 +99,27 @@ describe('when using the ganttDb', function () { } ); + it('should handle milliseconds', function () { + ganttDb.setDateFormat('x'); + ganttDb.addSection('testa1'); + ganttDb.addTask('test1', 'id1,0,20ms'); + ganttDb.addTask('test2', 'id2,after id1,5ms'); + ganttDb.addSection('testa2'); + ganttDb.addTask('test3', 'id3,20,10ms'); + ganttDb.addTask('test4', 'id4,after id3,5ms'); + + const tasks = ganttDb.getTasks(); + + expect(tasks[0].startTime.toISOString()).toEqual('1970-01-01T00:00:00.000Z'); + expect(tasks[0].endTime.toISOString()).toEqual('1970-01-01T00:00:00.020Z'); + expect(tasks[1].startTime.toISOString()).toEqual('1970-01-01T00:00:00.020Z'); + expect(tasks[1].endTime.toISOString()).toEqual('1970-01-01T00:00:00.025Z'); + expect(tasks[2].startTime.toISOString()).toEqual('1970-01-01T00:00:00.020Z'); + expect(tasks[2].endTime.toISOString()).toEqual('1970-01-01T00:00:00.030Z'); + expect(tasks[3].startTime.toISOString()).toEqual('1970-01-01T00:00:00.030Z'); + expect(tasks[3].endTime.toISOString()).toEqual('1970-01-01T00:00:00.035Z'); + }); + it('should handle relative start date based on id regardless of sections', function () { ganttDb.setDateFormat('YYYY-MM-DD'); ganttDb.addSection('testa1'); From 86b3a4f09e7ec590d0880343a83c302259c36ade Mon Sep 17 00:00:00 2001 From: Amy Qualls <1157888+amyq@users.noreply.github.com> Date: Thu, 25 Aug 2022 12:01:55 -0700 Subject: [PATCH 04/20] Document line curve options An extremely basic MVC explaining that it is possible to adjust how lines in a flowchart are curved, while listing (some of?) the available options. I doubt I've captured all of the curve options, but capturing the existence of curve options is a start. Sources: - https://github.com/mermaid-js/mermaid/issues/580#issuecomment-373929046 where a user references adding the feature to Mermaid - Which references https://github.com/d3/d3-shape/blob/master/README.md#curves and I think is worth including here --- docs/flowchart.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/flowchart.md b/docs/flowchart.md index 7631a7f46..433bd8fa0 100644 --- a/docs/flowchart.md +++ b/docs/flowchart.md @@ -522,6 +522,22 @@ In the example below the style defined in the linkStyle statement will belong to linkStyle 3 stroke:#ff3,stroke-width:4px,color:red; ``` +### Styling line curves + +It is possible to style the type of curve used for lines between items, if the default method does not meet your needs. +Available curve styles include `basis`, `bump`, `linear`, `monotoneX`, `monotoneY`, `natural`, `step`, `stepAfter`, +and `stepBefore`. + +In this example, a left-to-right graph uses the `stepBefore` curve style: + +``` +%%{ init: { 'flowchart': { 'curve': 'stepBefore' } } }%% +graph LR +``` + +For a full list of available curves, including an explanation of custom curves, refer to +the [Shapes](https://github.com/d3/d3-shape/blob/main/README.md#curves) documentation in the +[d3-shape](https://github.com/d3/d3-shape/) project. ### Styling a node From b2f5ba3ee8a902fa16b7c9f4a189564def22bab5 Mon Sep 17 00:00:00 2001 From: Alois Klink Date: Thu, 25 Aug 2022 23:18:13 +0100 Subject: [PATCH 05/20] feat(git): allow custom merge commit ids Currently, merge commits can have a git tag, but they cannot have a custom git commit ID. This commit allows modifying the default merge commit id. It also displays all merge commits IDs, which undoes https://github.com/mermaid-js/mermaid/commit/3ccf027f4285ba89bba13de62d05d0ce58ac79b5 --- .../integration/rendering/gitGraph.spec.js | 4 +- docs/gitgraph.md | 2 + src/diagrams/git/gitGraphAst.js | 13 +++- src/diagrams/git/gitGraphParserV2.spec.js | 70 +++++++++++++++++++ src/diagrams/git/gitGraphRenderer.js | 6 +- src/diagrams/git/parser/gitGraph.jison | 3 + 6 files changed, 89 insertions(+), 9 deletions(-) diff --git a/cypress/integration/rendering/gitGraph.spec.js b/cypress/integration/rendering/gitGraph.spec.js index 283a52c67..52019c430 100644 --- a/cypress/integration/rendering/gitGraph.spec.js +++ b/cypress/integration/rendering/gitGraph.spec.js @@ -74,7 +74,7 @@ describe('Git Graph diagram', () => { {} ); }); - it('7: should render a simple gitgraph with three branches and merge commit', () => { + it('7: should render a simple gitgraph with three branches and tagged merge commit', () => { imgSnapshotTest( `gitGraph commit id: "1" @@ -93,7 +93,7 @@ describe('Git Graph diagram', () => { checkout nice_feature commit id: "7" checkout main - merge nice_feature + merge nice_feature id: "12345" tag: "my merge commit" checkout very_nice_feature commit id: "8" checkout main diff --git a/docs/gitgraph.md b/docs/gitgraph.md index a083fcc2f..53e802101 100644 --- a/docs/gitgraph.md +++ b/docs/gitgraph.md @@ -182,6 +182,8 @@ After this we made use of the `checkout` keyword to set the current branch as `m After this we merge the `develop` branch onto the current branch `main`, resulting in a merge commit. Since the current branch at this point is still `main`, the last two commits are registered against that. +Additionally, you may add a tag to the merge commit, or override the default id: `merge branch id:"1234" tag:"v1.0.0"` + ### Cherry Pick commit from another branch Similar to how 'git' allows you to cherry-pick a commit from **another branch** onto the **current** branch, Mermaid also supports this functionality. You can also cherry-pick a commit from another branch using the `cherry-pick` keyword. diff --git a/src/diagrams/git/gitGraphAst.js b/src/diagrams/git/gitGraphAst.js index 2e7dc601a..6cec8bdd8 100644 --- a/src/diagrams/git/gitGraphAst.js +++ b/src/diagrams/git/gitGraphAst.js @@ -148,8 +148,17 @@ export const branch = function (name, order) { } }; -export const merge = function (otherBranch, tag) { +/** + * Creates a merge commit. + * + * @param {string} otherBranch - Target branch to merge to. + * @param {string} [tag] - Git tag to use on this merge commit. + * @param {string} [id] - Git commit id. + */ +export const merge = function (otherBranch, tag, id) { otherBranch = common.sanitizeText(otherBranch, configApi.getConfig()); + id = common.sanitizeText(id, configApi.getConfig()); + const currentCommit = commits[branches[curBranch]]; const otherCommit = commits[branches[otherBranch]]; if (curBranch === otherBranch) { @@ -219,7 +228,7 @@ export const merge = function (otherBranch, tag) { // } else { // create merge commit const commit = { - id: seq + '-' + getId(), + id: id || seq + '-' + getId(), message: 'merged branch ' + otherBranch + ' into ' + curBranch, seq: seq++, parents: [head == null ? null : head.id, branches[otherBranch]], diff --git a/src/diagrams/git/gitGraphParserV2.spec.js b/src/diagrams/git/gitGraphParserV2.spec.js index b57ce1af0..9c8e47443 100644 --- a/src/diagrams/git/gitGraphParserV2.spec.js +++ b/src/diagrams/git/gitGraphParserV2.spec.js @@ -496,6 +496,76 @@ describe('when parsing a gitGraph', function () { ]); }); + it('should handle merge ids', function () { + const str = `gitGraph: + commit + branch testBranch + checkout testBranch + commit + checkout main + %% Merge Tag and ID + merge testBranch tag: "merge-tag" id: "2-222" + branch testBranch2 + checkout testBranch2 + commit + checkout main + %% Merge ID and Tag (reverse order) + merge testBranch2 id: "4-444" tag: "merge-tag2" + branch testBranch3 + checkout testBranch3 + commit + checkout main + %% just Merge ID + merge testBranch3 id: "6-666" + `; + + parser.parse(str); + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(7); + expect(parser.yy.getCurrentBranch()).toBe('main'); + expect(parser.yy.getDirection()).toBe('LR'); + + // The order of these commits is in alphabetical order of IDs + const [ + mainCommit, + testBranchCommit, + testBranchMerge, + testBranch2Commit, + testBranch2Merge, + testBranch3Commit, + testBranch3Merge, + ] = Object.values(commits); + + console.log(Object.keys(commits)); + + expect(mainCommit.branch).toBe('main'); + expect(mainCommit.parents).toStrictEqual([]); + + expect(testBranchCommit.branch).toBe('testBranch'); + expect(testBranchCommit.parents).toStrictEqual([mainCommit.id]); + + expect(testBranchMerge.branch).toBe('main'); + expect(testBranchMerge.parents).toStrictEqual([mainCommit.id, testBranchCommit.id]); + expect(testBranchMerge.tag).toBe('merge-tag'); + expect(testBranchMerge.id).toBe('2-222'); + + expect(testBranch2Merge.branch).toBe('main'); + expect(testBranch2Merge.parents).toStrictEqual([testBranchMerge.id, testBranch2Commit.id]); + expect(testBranch2Merge.tag).toBe('merge-tag2'); + expect(testBranch2Merge.id).toBe('4-444'); + + expect(testBranch3Merge.branch).toBe('main'); + expect(testBranch3Merge.parents).toStrictEqual([testBranch2Merge.id, testBranch3Commit.id]); + expect(testBranch3Merge.id).toBe('6-666'); + + expect(parser.yy.getBranchesAsObjArray()).toStrictEqual([ + { name: 'main' }, + { name: 'testBranch' }, + { name: 'testBranch2' }, + { name: 'testBranch3' }, + ]); + }); + it('should throw error when try to branch existing branch: main', function () { const str = `gitGraph commit diff --git a/src/diagrams/git/gitGraphRenderer.js b/src/diagrams/git/gitGraphRenderer.js index 0a7c457cf..7dce4d748 100644 --- a/src/diagrams/git/gitGraphRenderer.js +++ b/src/diagrams/git/gitGraphRenderer.js @@ -215,11 +215,7 @@ const drawCommits = (svg, commits, modifyGraph) => { const px = 4; const py = 2; // Draw the commit label - if ( - commit.type !== commitType.CHERRY_PICK && - commit.type !== commitType.MERGE && - gitGraphConfig.showCommitLabel - ) { + if (commit.type !== commitType.CHERRY_PICK && gitGraphConfig.showCommitLabel) { const wrapper = gLabels.append('g'); const labelBkg = wrapper.insert('rect').attr('class', 'commit-label-bkg'); diff --git a/src/diagrams/git/parser/gitGraph.jison b/src/diagrams/git/parser/gitGraph.jison index 04b208249..c7f1fbe27 100644 --- a/src/diagrams/git/parser/gitGraph.jison +++ b/src/diagrams/git/parser/gitGraph.jison @@ -123,6 +123,9 @@ cherryPickStatement mergeStatement : MERGE ID {yy.merge($2)} | MERGE ID COMMIT_TAG STR {yy.merge($2, $4)} + | MERGE ID COMMIT_ID STR {yy.merge($2, '', $4)} + | MERGE ID COMMIT_TAG STR COMMIT_ID STR {yy.merge($2, $4, $6)} + | MERGE ID COMMIT_ID STR COMMIT_TAG STR {yy.merge($2, $6, $4)} ; commitStatement From 0779c39654abbca3764fd3c2e79936b8f9082587 Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Sat, 27 Aug 2022 12:32:33 +0200 Subject: [PATCH 06/20] Border --- cypress/platform/knsv.html | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/cypress/platform/knsv.html b/cypress/platform/knsv.html index 3c045d2c8..f1420e93a 100644 --- a/cypress/platform/knsv.html +++ b/cypress/platform/knsv.html @@ -22,6 +22,9 @@ .mermaid2,.mermaid3 { display: none; } + .mermaid { + border: 1px solid purple; + } .mermaid svg { /* font-size: 18px !important; */ } @@ -52,11 +55,23 @@ flowchart LR click O0 function "Lots of great info about Joe
Lots of great info about Joe
burt
fred";
-classDiagram-v2 - class Shape - link Shape "https://www.github.com" "This is a
tooltip
for a link" - class Shape2 - click Shape2 href "https://www.github.com" "This is a tooltip for a link" +flowchart TD + subgraph test + direction TB + subgraph test2 + direction LR + F --> D + end + subgraph test3 + direction TB + G --> H + end + end + + A --> B + A --> C + B --> C +
gitGraph @@ -308,8 +323,8 @@ flowchart TD securityLevel: 'loose', logLevel: 0, flowchart: { - curve: 'basis', - useMaxWidth: false, + curve: 'curveLinear', + useMaxWidth: true, htmlLabels: true, }, }); From 2968b400c49f66983e6d206959504e72aa6ae0ef Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Sat, 27 Aug 2022 15:03:29 +0200 Subject: [PATCH 07/20] Updated viewBox settings --- .../rendering/flowchart-v2.spec.js | 15 +++++- cypress/platform/knsv.html | 48 ++++++++++++------- src/diagrams/flowchart/flowRenderer-v2.js | 4 +- src/utils.js | 21 +++++--- 4 files changed, 60 insertions(+), 28 deletions(-) diff --git a/cypress/integration/rendering/flowchart-v2.spec.js b/cypress/integration/rendering/flowchart-v2.spec.js index 10731de05..cc0362dd0 100644 --- a/cypress/integration/rendering/flowchart-v2.spec.js +++ b/cypress/integration/rendering/flowchart-v2.spec.js @@ -42,7 +42,7 @@ describe('Flowchart v2', () => { P3 --> P6 P1.5 --> P5 `, - { flowchart: { diagramPadding: 0 } } + {} ); }); @@ -60,7 +60,7 @@ describe('Flowchart v2', () => { C <-...-> E4 C ======> E5 `, - { flowchart: { diagramPadding: 0 } } + {} ); }); it('5: should render escaped without html labels', () => { @@ -652,4 +652,15 @@ flowchart RL { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' } ); }); + it('2824: Clipping of edges', () => { + imgSnapshotTest( + ` + flowchart TD + A --> B + A --> C + B --> C + `, + { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' } + ); + }); }); diff --git a/cypress/platform/knsv.html b/cypress/platform/knsv.html index f1420e93a..29c83ff1a 100644 --- a/cypress/platform/knsv.html +++ b/cypress/platform/knsv.html @@ -23,10 +23,12 @@ display: none; } .mermaid { - border: 1px solid purple; + } .mermaid svg { + border: 1px solid purple; /* font-size: 18px !important; */ + fontFamily: 'courier' } @@ -35,7 +37,7 @@ -
+
flowchart LR classDef aPID stroke:#4e4403,fill:#fdde29,color:#4e4403,rx:5px,ry:5px; classDef crm stroke:#333333,fill:#DCDCDC,color:#333333,rx:5px,ry:5px; @@ -54,7 +56,7 @@ flowchart LR O0 -- has type -->O2["Bug"] click O0 function "Lots of great info about Joe
Lots of great info about Joe
burt
fred";
-
+
flowchart TD subgraph test direction TB @@ -68,22 +70,30 @@ flowchart TD end end +
+
+flowchart LR + a["Haiya"]===>b +
+
+flowchart TD A --> B A --> C B --> C -
-
- gitGraph - commit - commit - branch develop - commit - commit - commit - checkout main - commit - commit +
+flowchart TD + A([stadium shape test]) + A -->|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
wroom wroom]) + click A "index.html#link-clicked" "link test" + click B testClick "click test" + classDef someclass fill:#f96; + class A someclass; + class C someclass;
sequenceDiagram @@ -273,7 +283,7 @@ flowchart TD C -->|One| D[Laptop] C -->|Two| E[iPhone] C -->|Three| F[fa:fa-car Car] -
+
classDiagram Animal "1" <|-- Duck Animal <|-- Fish @@ -322,10 +332,12 @@ flowchart TD startOnLoad: true, securityLevel: 'loose', logLevel: 0, + fontFamily: 'courier', flowchart: { - curve: 'curveLinear', + // curve: 'curveLinear', useMaxWidth: true, - htmlLabels: true, + htmlLabels: false, + fontFamily: 'courier', }, }); function callback() { diff --git a/src/diagrams/flowchart/flowRenderer-v2.js b/src/diagrams/flowchart/flowRenderer-v2.js index 9fc28f266..103addbfc 100644 --- a/src/diagrams/flowchart/flowRenderer-v2.js +++ b/src/diagrams/flowchart/flowRenderer-v2.js @@ -388,8 +388,8 @@ export const draw = function (text, id, _version, diagObj) { rankdir: dir, nodesep: nodeSpacing, ranksep: rankSpacing, - marginx: 8, - marginy: 8, + marginx: 0, + marginy: 0, }) .setDefaultEdgeLabel(function () { return {}; diff --git a/src/utils.js b/src/utils.js index db45ab9f6..7e5c9a0da 100644 --- a/src/utils.js +++ b/src/utils.js @@ -742,12 +742,12 @@ const d3Attrs = function (d3Elem, attrs) { */ export const calculateSvgSizeAttrs = function (height, width, useMaxWidth) { let attrs = new Map(); - attrs.set('height', height); + // attrs.set('height', height); if (useMaxWidth) { attrs.set('width', '100%'); - attrs.set('style', `max-width: ${width}px;`); + attrs.set('style', `max-width: ${width * 1.2}px;`); } else { - attrs.set('width', width); + attrs.set('width', width * 1.2); } return attrs; }; @@ -769,8 +769,12 @@ export const setupGraphViewbox = function (graph, svgElem, padding, useMaxWidth) const sWidth = svgBounds.width; const sHeight = svgBounds.height; + log.info(`SVG bounds: ${sWidth}x${sHeight}`, svgBounds); + let width = graph._label.width; let height = graph._label.height; + log.info(`Graph bounds: ${width}x${height}`, graph); + let tx = 0; let ty = 0; if (sWidth > width) { @@ -785,11 +789,16 @@ export const setupGraphViewbox = function (graph, svgElem, padding, useMaxWidth) ty = (sHeight - height) / 2 + padding; height = sHeight + padding * 2; } + + log.info(`Calculated bounds: ${width}x${height}`); configureSvgSize(svgElem, height, width, useMaxWidth); // Ensure the viewBox includes the whole svgBounds area with extra space for padding - const vBox = `0 0 ${width} ${height}`; - log.debug( + // const vBox = `0 0 ${width} ${height}`; + const vBox = `${svgBounds.x - padding} ${svgBounds.y - padding} ${ + svgBounds.width + 2 * padding + } ${svgBounds.height + 2 * padding}`; + log.info( 'Graph.label', graph._label, 'swidth', @@ -808,7 +817,7 @@ export const setupGraphViewbox = function (graph, svgElem, padding, useMaxWidth) vBox ); svgElem.attr('viewBox', vBox); - svgElem.select('g').attr('transform', `translate(${tx}, ${ty})`); + // svgElem.select('g').attr('transform', `translate(${tx}, ${ty})`); }; export const initIdGenerator = class iterator { From 3b93c392499281d87071e657f56fe5ebd71cfc7d Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Sat, 27 Aug 2022 15:11:43 +0200 Subject: [PATCH 08/20] Adjusting size and test --- src/utils.js | 6 +++--- src/utils.spec.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/utils.js b/src/utils.js index 7e5c9a0da..561492825 100644 --- a/src/utils.js +++ b/src/utils.js @@ -745,9 +745,9 @@ export const calculateSvgSizeAttrs = function (height, width, useMaxWidth) { // attrs.set('height', height); if (useMaxWidth) { attrs.set('width', '100%'); - attrs.set('style', `max-width: ${width * 1.2}px;`); + attrs.set('style', `max-width: ${width}px;`); } else { - attrs.set('width', width * 1.2); + attrs.set('width', width); } return attrs; }; @@ -761,7 +761,7 @@ export const calculateSvgSizeAttrs = function (height, width, useMaxWidth) { * @param {boolean} useMaxWidth Whether or not to use max-width and set width to 100% */ export const configureSvgSize = function (svgElem, height, width, useMaxWidth) { - const attrs = calculateSvgSizeAttrs(height, width, useMaxWidth); + const attrs = calculateSvgSizeAttrs(height, 1.1 * width, useMaxWidth); d3Attrs(svgElem, attrs); }; export const setupGraphViewbox = function (graph, svgElem, padding, useMaxWidth) { diff --git a/src/utils.spec.js b/src/utils.spec.js index 7eb3af9ff..82b76194c 100644 --- a/src/utils.spec.js +++ b/src/utils.spec.js @@ -294,13 +294,13 @@ describe('when formatting urls', function () { describe('when calculating SVG size', function () { it('should return width 100% when useMaxWidth is true', function () { const attrs = utils.calculateSvgSizeAttrs(100, 200, true); - expect(attrs.get('height')).toEqual(100); + // expect(attrs.get('height')).toEqual(100); expect(attrs.get('style')).toEqual('max-width: 200px;'); expect(attrs.get('width')).toEqual('100%'); }); it('should return absolute width when useMaxWidth is false', function () { const attrs = utils.calculateSvgSizeAttrs(100, 200, false); - expect(attrs.get('height')).toEqual(100); + // expect(attrs.get('height')).toEqual(100); expect(attrs.get('width')).toEqual(200); }); }); From b7f9495a1434e620ff475d46b6c98834ce34bc77 Mon Sep 17 00:00:00 2001 From: Alois Klink Date: Sat, 27 Aug 2022 17:32:29 +0100 Subject: [PATCH 09/20] build: add eslint --cache file Currently, doing a `git commit` is a bit low, as eslint runs before the commit. Adding an `eslint --cache` makes it slightly faster. On my PC, `git commit` currently is `Done in 12.24s.` However, after adding this cache file, it is `Done in 7.54s.`, so about 1.6x faster. --- .gitignore | 5 ++++- package.json | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 8ce4bf724..c5c4338e5 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,7 @@ Gemfile.lock /.vs cypress/screenshots/ -cypress/snapshots/ \ No newline at end of file +cypress/snapshots/ + +# eslint --cache file +.eslintcache diff --git a/package.json b/package.json index 065d8d6da..8c05cb17c 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "postbuild": "documentation build src/mermaidAPI.js src/config.js src/defaultConfig.js --shallow -f md --markdown-toc false > docs/Setup.md", "build:watch": "yarn build:development --watch", "release": "yarn build", - "lint": "eslint ./ --ext .js,.json,.html,.md", + "lint": "eslint --cache ./ --ext .js,.json,.html,.md", "lint:fix": "yarn lint --fix", "e2e:depr": "yarn lint && jest e2e --config e2e/jest.config.js", "cypress": "cypress run", From e6e7bdcb554d5f7151abd59cb97e460798f95775 Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Sun, 28 Aug 2022 11:25:09 +0200 Subject: [PATCH 10/20] #2824 Size changes and updated regressionstest afters diagram sizing changes --- .../integration/rendering/erDiagram.spec.js | 18 +++++----- .../rendering/flowchart-v2.spec.js | 10 +++--- .../integration/rendering/flowchart.spec.js | 10 +++--- cypress/integration/rendering/gantt.spec.js | 6 ++-- cypress/integration/rendering/journey.spec.js | 4 +-- cypress/integration/rendering/pie.spec.js | 6 ++-- .../rendering/sequencediagram.spec.js | 10 +++--- .../rendering/stateDiagram-v2.spec.js | 6 ++-- .../rendering/stateDiagram.spec.js | 10 +++--- cypress/platform/knsv.html | 12 ++++--- docs/index.html | 4 +-- src/diagrams/state/stateRenderer-v2.js | 2 +- src/utils.js | 36 +++++++++---------- 13 files changed, 68 insertions(+), 66 deletions(-) diff --git a/cypress/integration/rendering/erDiagram.spec.js b/cypress/integration/rendering/erDiagram.spec.js index 781a8ca25..0f9084e7c 100644 --- a/cypress/integration/rendering/erDiagram.spec.js +++ b/cypress/integration/rendering/erDiagram.spec.js @@ -112,7 +112,7 @@ describe('Entity Relationship Diagram', () => { ); cy.get('svg').should((svg) => { expect(svg).to.have.attr('width', '100%'); - expect(svg).to.have.attr('height', '465'); + // expect(svg).to.have.attr('height', '465'); const style = svg.attr('style'); expect(style).to.match(/^max-width: [\d.]+px;$/); const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join('')); @@ -134,7 +134,7 @@ describe('Entity Relationship Diagram', () => { const width = parseFloat(svg.attr('width')); // use within because the absolute value can be slightly different depending on the environment ±5% expect(width).to.be.within(140 * 0.95, 140 * 1.05); - expect(svg).to.have.attr('height', '465'); + // expect(svg).to.have.attr('height', '465'); expect(svg).to.not.have.attr('style'); }); }); @@ -186,7 +186,7 @@ describe('Entity Relationship Diagram', () => { renderGraph( ` erDiagram - PRIVATE_FINANCIAL_INSTITUTION { + PRIVATE_FINANCIAL_INSTITUTION { string name int turnover } @@ -206,9 +206,9 @@ describe('Entity Relationship Diagram', () => { string name PK } AUTHOR_WITH_LONG_ENTITY_NAME }|..|{ BOOK : writes - BOOK { + BOOK { float price - string author FK + string author FK string title PK } `, @@ -225,8 +225,8 @@ describe('Entity Relationship Diagram', () => { string name "comment" } AUTHOR_WITH_LONG_ENTITY_NAME }|..|{ BOOK : writes - BOOK { - string author + BOOK { + string author string title "author comment" float price "price comment" } @@ -244,11 +244,11 @@ describe('Entity Relationship Diagram', () => { string name PK "comment" } AUTHOR_WITH_LONG_ENTITY_NAME }|..|{ BOOK : writes - BOOK { + BOOK { string description float price "price comment" string title PK "title comment" - string author FK + string author FK } `, { logLevel: 1 } diff --git a/cypress/integration/rendering/flowchart-v2.spec.js b/cypress/integration/rendering/flowchart-v2.spec.js index cc0362dd0..61dccfb84 100644 --- a/cypress/integration/rendering/flowchart-v2.spec.js +++ b/cypress/integration/rendering/flowchart-v2.spec.js @@ -92,10 +92,10 @@ describe('Flowchart v2', () => { ); cy.get('svg').should((svg) => { expect(svg).to.have.attr('width', '100%'); - expect(svg).to.have.attr('height'); + // expect(svg).to.have.attr('height'); // use within because the absolute value can be slightly different depending on the environment ±5% - const height = parseFloat(svg.attr('height')); - expect(height).to.be.within(446 * 0.95, 446 * 1.05); + // const height = parseFloat(svg.attr('height')); + // expect(height).to.be.within(446 * 0.95, 446 * 1.05); const style = svg.attr('style'); expect(style).to.match(/^max-width: [\d.]+px;$/); const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join('')); @@ -114,10 +114,10 @@ describe('Flowchart v2', () => { { flowchart: { useMaxWidth: false } } ); cy.get('svg').should((svg) => { - const height = parseFloat(svg.attr('height')); + // const height = parseFloat(svg.attr('height')); const width = parseFloat(svg.attr('width')); // use within because the absolute value can be slightly different depending on the environment ±5% - expect(height).to.be.within(446 * 0.95, 446 * 1.05); + // expect(height).to.be.within(446 * 0.95, 446 * 1.05); expect(width).to.be.within(290 * 0.95 - 1, 290 * 1.05); expect(svg).to.not.have.attr('style'); }); diff --git a/cypress/integration/rendering/flowchart.spec.js b/cypress/integration/rendering/flowchart.spec.js index cbdcc4ebd..b4e94d1ab 100644 --- a/cypress/integration/rendering/flowchart.spec.js +++ b/cypress/integration/rendering/flowchart.spec.js @@ -744,10 +744,10 @@ describe('Graph', () => { ); cy.get('svg').should((svg) => { expect(svg).to.have.attr('width', '100%'); - expect(svg).to.have.attr('height'); + // expect(svg).to.have.attr('height'); // use within because the absolute value can be slightly different depending on the environment ±5% - const height = parseFloat(svg.attr('height')); - expect(height).to.be.within(446 * 0.95, 446 * 1.05); + // const height = parseFloat(svg.attr('height')); + // expect(height).to.be.within(446 * 0.95, 446 * 1.05); const style = svg.attr('style'); expect(style).to.match(/^max-width: [\d.]+px;$/); const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join('')); @@ -766,10 +766,10 @@ describe('Graph', () => { { flowchart: { useMaxWidth: false } } ); cy.get('svg').should((svg) => { - const height = parseFloat(svg.attr('height')); + // const height = parseFloat(svg.attr('height')); const width = parseFloat(svg.attr('width')); // use within because the absolute value can be slightly different depending on the environment ±5% - expect(height).to.be.within(446 * 0.95, 446 * 1.05); + // expect(height).to.be.within(446 * 0.95, 446 * 1.05); expect(width).to.be.within(300 * 0.95, 300 * 1.05); expect(svg).to.not.have.attr('style'); }); diff --git a/cypress/integration/rendering/gantt.spec.js b/cypress/integration/rendering/gantt.spec.js index 7dc7c6cf5..8b249a100 100644 --- a/cypress/integration/rendering/gantt.spec.js +++ b/cypress/integration/rendering/gantt.spec.js @@ -218,10 +218,10 @@ describe('Gantt diagram', () => { ); cy.get('svg').should((svg) => { expect(svg).to.have.attr('width', '100%'); - expect(svg).to.have.attr('height'); + // expect(svg).to.have.attr('height'); // use within because the absolute value can be slightly different depending on the environment ±5% - const height = parseFloat(svg.attr('height')); - expect(height).to.be.within(484 * 0.95, 484 * 1.05); + // const height = parseFloat(svg.attr('height')); + // expect(height).to.be.within(484 * 0.95, 484 * 1.05); const style = svg.attr('style'); expect(style).to.match(/^max-width: [\d.]+px;$/); const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join('')); diff --git a/cypress/integration/rendering/journey.spec.js b/cypress/integration/rendering/journey.spec.js index 5f13e5b89..6f9d9bb60 100644 --- a/cypress/integration/rendering/journey.spec.js +++ b/cypress/integration/rendering/journey.spec.js @@ -42,8 +42,8 @@ section Checkout from website cy.get('svg').should((svg) => { expect(svg).to.have.attr('width', '100%'); expect(svg).to.have.attr('height'); - const height = parseFloat(svg.attr('height')); - expect(height).to.eq(565); + // const height = parseFloat(svg.attr('height')); + // expect(height).to.eq(565); const style = svg.attr('style'); expect(style).to.match(/^max-width: [\d.]+px;$/); const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join('')); diff --git a/cypress/integration/rendering/pie.spec.js b/cypress/integration/rendering/pie.spec.js index 233e716ed..ced4aedcf 100644 --- a/cypress/integration/rendering/pie.spec.js +++ b/cypress/integration/rendering/pie.spec.js @@ -48,9 +48,9 @@ describe('Pie Chart', () => { ); cy.get('svg').should((svg) => { expect(svg).to.have.attr('width', '100%'); - expect(svg).to.have.attr('height'); - const height = parseFloat(svg.attr('height')); - expect(height).to.eq(450); + // expect(svg).to.have.attr('height'); + // const height = parseFloat(svg.attr('height')); + // expect(height).to.eq(450); const style = svg.attr('style'); expect(style).to.match(/^max-width: [\d.]+px;$/); const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join('')); diff --git a/cypress/integration/rendering/sequencediagram.spec.js b/cypress/integration/rendering/sequencediagram.spec.js index f1def3391..b5ff92c8c 100644 --- a/cypress/integration/rendering/sequencediagram.spec.js +++ b/cypress/integration/rendering/sequencediagram.spec.js @@ -734,9 +734,9 @@ context('Sequence diagram', () => { ); cy.get('svg').should((svg) => { expect(svg).to.have.attr('width', '100%'); - expect(svg).to.have.attr('height'); - const height = parseFloat(svg.attr('height')); - expect(height).to.be.within(920, 971); + // expect(svg).to.have.attr('height'); + // const height = parseFloat(svg.attr('height')); + // expect(height).to.be.within(920, 971); const style = svg.attr('style'); expect(style).to.match(/^max-width: [\d.]+px;$/); const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join('')); @@ -773,9 +773,9 @@ context('Sequence diagram', () => { { sequence: { useMaxWidth: false } } ); cy.get('svg').should((svg) => { - const height = parseFloat(svg.attr('height')); + // const height = parseFloat(svg.attr('height')); const width = parseFloat(svg.attr('width')); - expect(height).to.be.within(920, 971); + // expect(height).to.be.within(920, 971); // use within because the absolute value can be slightly different depending on the environment ±5% expect(width).to.be.within(820 * 0.95, 820 * 1.05); expect(svg).to.not.have.attr('style'); diff --git a/cypress/integration/rendering/stateDiagram-v2.spec.js b/cypress/integration/rendering/stateDiagram-v2.spec.js index 946b5d31e..d4b43e9c6 100644 --- a/cypress/integration/rendering/stateDiagram-v2.spec.js +++ b/cypress/integration/rendering/stateDiagram-v2.spec.js @@ -480,9 +480,9 @@ stateDiagram-v2 ); cy.get('svg').should((svg) => { expect(svg).to.have.attr('width', '100%'); - expect(svg).to.have.attr('height'); - const height = parseFloat(svg.attr('height')); - expect(height).to.be.within(177, 178); + // expect(svg).to.have.attr('height'); + // const height = parseFloat(svg.attr('height')); + // expect(height).to.be.within(177, 178); const style = svg.attr('style'); expect(style).to.match(/^max-width: [\d.]+px;$/); const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join('')); diff --git a/cypress/integration/rendering/stateDiagram.spec.js b/cypress/integration/rendering/stateDiagram.spec.js index 4e538f219..c2fb7a977 100644 --- a/cypress/integration/rendering/stateDiagram.spec.js +++ b/cypress/integration/rendering/stateDiagram.spec.js @@ -357,9 +357,9 @@ describe('State diagram', () => { ); cy.get('svg').should((svg) => { expect(svg).to.have.attr('width', '100%'); - expect(svg).to.have.attr('height'); - const height = parseFloat(svg.attr('height')); - expect(height).to.be.within(176, 178); + // expect(svg).to.have.attr('height'); + // const height = parseFloat(svg.attr('height')); + // expect(height).to.be.within(176, 178); const style = svg.attr('style'); expect(style).to.match(/^max-width: [\d.]+px;$/); const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join('')); @@ -379,9 +379,9 @@ describe('State diagram', () => { { state: { useMaxWidth: false } } ); cy.get('svg').should((svg) => { - const height = parseFloat(svg.attr('height')); + // const height = parseFloat(svg.attr('height')); const width = parseFloat(svg.attr('width')); - expect(height).to.be.within(176, 178); + // expect(height).to.be.within(176, 178); // use within because the absolute value can be slightly different depending on the environment ±5% // Todo investigate difference // expect(width).to.be.within(112 * .95, 112 * 1.05); diff --git a/cypress/platform/knsv.html b/cypress/platform/knsv.html index 29c83ff1a..f568c9a5d 100644 --- a/cypress/platform/knsv.html +++ b/cypress/platform/knsv.html @@ -37,7 +37,7 @@ -
+
flowchart LR classDef aPID stroke:#4e4403,fill:#fdde29,color:#4e4403,rx:5px,ry:5px; classDef crm stroke:#333333,fill:#DCDCDC,color:#333333,rx:5px,ry:5px; @@ -72,16 +72,20 @@ flowchart TD
+flowchart TD +id +
+
flowchart LR a["Haiya"]===>b
-
+
flowchart TD A --> B A --> C B --> C
-
+
flowchart TD A([stadium shape test]) A -->|Get money| B([Go shopping]) @@ -283,7 +287,7 @@ flowchart TD C -->|One| D[Laptop] C -->|Two| E[iPhone] C -->|Three| F[fa:fa-car Car] -
+
classDiagram Animal "1" <|-- Duck Animal <|-- Fish diff --git a/docs/index.html b/docs/index.html index 64cc726bc..c48a37562 100644 --- a/docs/index.html +++ b/docs/index.html @@ -18,8 +18,8 @@ - - + + + +