Skip to content

Commit e9e663f

Browse files
Merge pull request #6198 from mermaid-js/edge-flicker-fix
edge flickering fix
2 parents eb76dfb + 963efa6 commit e9e663f

File tree

6 files changed

+96
-12
lines changed

6 files changed

+96
-12
lines changed

.changeset/bright-ads-exist.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'mermaid': patch
3+
---
4+
5+
Fixes for consistent edge id creation & handling edge cases for animate edge feature

docs/config/setup/interfaces/mermaid.LayoutData.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
#### Defined in
2222

23-
[packages/mermaid/src/rendering-util/types.ts:147](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L147)
23+
[packages/mermaid/src/rendering-util/types.ts:148](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L148)
2424

2525
---
2626

@@ -30,7 +30,7 @@
3030

3131
#### Defined in
3232

33-
[packages/mermaid/src/rendering-util/types.ts:146](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L146)
33+
[packages/mermaid/src/rendering-util/types.ts:147](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L147)
3434

3535
---
3636

@@ -40,4 +40,4 @@
4040

4141
#### Defined in
4242

43-
[packages/mermaid/src/rendering-util/types.ts:145](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L145)
43+
[packages/mermaid/src/rendering-util/types.ts:146](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L146)

packages/mermaid/src/diagrams/flowchart/flowDb.ts

+24-4
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,10 @@ export const addVertex = function (
9494
const edge = edges.find((e) => e.id === id);
9595
if (edge) {
9696
const edgeDoc = doc as EdgeMetaData;
97-
if (edgeDoc?.animate) {
97+
if (edgeDoc?.animate !== undefined) {
9898
edge.animate = edgeDoc.animate;
9999
}
100-
if (edgeDoc?.animation) {
100+
if (edgeDoc?.animation !== undefined) {
101101
edge.animation = edgeDoc.animation;
102102
}
103103
return;
@@ -212,6 +212,7 @@ export const addSingleLink = function (_start: string, _end: string, type: any,
212212
text: '',
213213
labelType: 'text',
214214
classes: [],
215+
isUserDefinedId: false,
215216
};
216217
log.info('abc78 Got edge...', edge);
217218
const linkTextObj = type.text;
@@ -231,8 +232,17 @@ export const addSingleLink = function (_start: string, _end: string, type: any,
231232
edge.stroke = type.stroke;
232233
edge.length = type.length > 10 ? 10 : type.length;
233234
}
234-
if (id) {
235+
236+
if (id && !edges.some((e) => e.id === id)) {
235237
edge.id = id;
238+
edge.isUserDefinedId = true;
239+
} else {
240+
const existingLinks = edges.filter((e) => e.start === edge.start && e.end === edge.end);
241+
if (existingLinks.length === 0) {
242+
edge.id = getEdgeId(edge.start, edge.end, { counter: 0, prefix: 'L' });
243+
} else {
244+
edge.id = getEdgeId(edge.start, edge.end, { counter: existingLinks.length + 1, prefix: 'L' });
245+
}
236246
}
237247

238248
if (edges.length < (config.maxEdges ?? 500)) {
@@ -267,9 +277,18 @@ export const addLink = function (_start: string[], _end: string[], linkData: unk
267277

268278
log.info('addLink', _start, _end, id);
269279

280+
// for a group syntax like A e1@--> B & C, only the first edge should have an the userDefined id
281+
// the rest of the edges should have auto generated ids
270282
for (const start of _start) {
271283
for (const end of _end) {
272-
addSingleLink(start, end, linkData, id);
284+
//use the id only for last node in _start and and first node in _end
285+
const isLastStart = start === _start[_start.length - 1];
286+
const isFirstEnd = end === _end[0];
287+
if (isLastStart && isFirstEnd) {
288+
addSingleLink(start, end, linkData, id);
289+
} else {
290+
addSingleLink(start, end, linkData, undefined);
291+
}
273292
}
274293
}
275294
};
@@ -1045,6 +1064,7 @@ export const getData = () => {
10451064
}
10461065
const edge: Edge = {
10471066
id: getEdgeId(rawEdge.start, rawEdge.end, { counter: index, prefix: 'L' }, rawEdge.id),
1067+
isUserDefinedId: rawEdge.isUserDefinedId,
10481068
start: rawEdge.start,
10491069
end: rawEdge.end,
10501070
type: rawEdge.type ?? 'normal',

packages/mermaid/src/diagrams/flowchart/parser/flow-node-data.spec.js

+62-5
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ describe('when parsing directions', function () {
251251
expect(data4Layout.nodes[0].shape).toEqual('squareRect');
252252
expect(data4Layout.nodes[0].label).toEqual('This is a<br/>multiline string');
253253
});
254-
it(' should be possible to use } in strings', function () {
254+
it('should be possible to use } in strings', function () {
255255
const res = flow.parser.parse(`flowchart TB
256256
A@{
257257
label: "This is a string with }"
@@ -264,7 +264,7 @@ describe('when parsing directions', function () {
264264
expect(data4Layout.nodes[0].shape).toEqual('squareRect');
265265
expect(data4Layout.nodes[0].label).toEqual('This is a string with }');
266266
});
267-
it(' should be possible to use @ in strings', function () {
267+
it('should be possible to use @ in strings', function () {
268268
const res = flow.parser.parse(`flowchart TB
269269
A@{
270270
label: "This is a string with @"
@@ -277,7 +277,7 @@ describe('when parsing directions', function () {
277277
expect(data4Layout.nodes[0].shape).toEqual('squareRect');
278278
expect(data4Layout.nodes[0].label).toEqual('This is a string with @');
279279
});
280-
it(' should be possible to use @ in strings', function () {
280+
it('should be possible to use @ in strings', function () {
281281
const res = flow.parser.parse(`flowchart TB
282282
A@{
283283
label: "This is a string with}"
@@ -291,7 +291,7 @@ describe('when parsing directions', function () {
291291
expect(data4Layout.nodes[0].label).toEqual('This is a string with}');
292292
});
293293

294-
it(' should be possible to use @ syntax to add labels on multi nodes', function () {
294+
it('should be possible to use @ syntax to add labels on multi nodes', function () {
295295
const res = flow.parser.parse(`flowchart TB
296296
n2["label for n2"] & n4@{ label: "labe for n4"} & n5@{ label: "labe for n5"}
297297
`);
@@ -343,7 +343,64 @@ describe('when parsing directions', function () {
343343
expect(data4Layout.nodes[9].label).toEqual('@for@ AS@');
344344
expect(data4Layout.nodes[10].label).toEqual('@for@ AS@');
345345
});
346-
it.skip(' should be possible to use @ syntax to add labels with trail spaces', function () {
346+
347+
it('should handle unique edge creation with using @ and &', function () {
348+
const res = flow.parser.parse(`flowchart TD
349+
A & B e1@--> C & D
350+
A1 e2@--> C1 & D1
351+
`);
352+
353+
const data4Layout = flow.parser.yy.getData();
354+
expect(data4Layout.nodes.length).toBe(7);
355+
expect(data4Layout.edges.length).toBe(6);
356+
expect(data4Layout.edges[0].id).toEqual('L_A_C_0');
357+
expect(data4Layout.edges[1].id).toEqual('L_A_D_0');
358+
expect(data4Layout.edges[2].id).toEqual('e1');
359+
expect(data4Layout.edges[3].id).toEqual('L_B_D_0');
360+
expect(data4Layout.edges[4].id).toEqual('e2');
361+
expect(data4Layout.edges[5].id).toEqual('L_A1_D1_0');
362+
});
363+
364+
it('should handle redefine same edge ids again', function () {
365+
const res = flow.parser.parse(`flowchart TD
366+
A & B e1@--> C & D
367+
A1 e1@--> C1 & D1
368+
`);
369+
370+
const data4Layout = flow.parser.yy.getData();
371+
expect(data4Layout.nodes.length).toBe(7);
372+
expect(data4Layout.edges.length).toBe(6);
373+
expect(data4Layout.edges[0].id).toEqual('L_A_C_0');
374+
expect(data4Layout.edges[1].id).toEqual('L_A_D_0');
375+
expect(data4Layout.edges[2].id).toEqual('e1');
376+
expect(data4Layout.edges[3].id).toEqual('L_B_D_0');
377+
expect(data4Layout.edges[4].id).toEqual('L_A1_C1_0');
378+
expect(data4Layout.edges[5].id).toEqual('L_A1_D1_0');
379+
});
380+
381+
it('should handle overriding edge animate again', function () {
382+
const res = flow.parser.parse(`flowchart TD
383+
A e1@--> B
384+
C e2@--> D
385+
E e3@--> F
386+
e1@{ animate: true }
387+
e2@{ animate: false }
388+
e3@{ animate: true }
389+
e3@{ animate: false }
390+
`);
391+
392+
const data4Layout = flow.parser.yy.getData();
393+
expect(data4Layout.nodes.length).toBe(6);
394+
expect(data4Layout.edges.length).toBe(3);
395+
expect(data4Layout.edges[0].id).toEqual('e1');
396+
expect(data4Layout.edges[0].animate).toEqual(true);
397+
expect(data4Layout.edges[1].id).toEqual('e2');
398+
expect(data4Layout.edges[1].animate).toEqual(false);
399+
expect(data4Layout.edges[2].id).toEqual('e3');
400+
expect(data4Layout.edges[2].animate).toEqual(false);
401+
});
402+
403+
it.skip('should be possible to use @ syntax to add labels with trail spaces', function () {
347404
const res = flow.parser.parse(
348405
`flowchart TB
349406
n2["label for n2"] & n4@{ label: "labe for n4"} & n5@{ label: "labe for n5"} `

packages/mermaid/src/diagrams/flowchart/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export interface FlowText {
5353
}
5454

5555
export interface FlowEdge {
56+
isUserDefinedId: boolean;
5657
start: string;
5758
end: string;
5859
interpolate?: string;

packages/mermaid/src/rendering-util/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ export interface Edge {
125125
pattern?: string;
126126
thickness?: 'normal' | 'thick' | 'invisible' | 'dotted';
127127
look?: string;
128+
isUserDefinedId?: boolean;
128129
}
129130

130131
export interface RectOptions {

0 commit comments

Comments
 (0)