mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-28 07:03:17 +08:00
#5574 Adding support for edge ids and animations
This commit is contained in:
parent
df636c6d0a
commit
9b00f1f2fb
@ -84,29 +84,66 @@
|
|||||||
/* tspan {
|
/* tspan {
|
||||||
font-size: 6px !important;
|
font-size: 6px !important;
|
||||||
} */
|
} */
|
||||||
|
/* .flowchart-link {
|
||||||
|
stroke-dasharray: 4, 4 !important;
|
||||||
|
animation: flow 1s linear infinite;
|
||||||
|
animation: dashdraw 4.93282s linear infinite;
|
||||||
|
stroke-width: 2px !important;
|
||||||
|
} */
|
||||||
|
|
||||||
|
@keyframes dashdraw {
|
||||||
|
from {
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*stroke-width:2;stroke-dasharray:10.000000,9.865639;stroke-dashoffset:-198.656393;animation: 4.932820s linear infinite;*/
|
||||||
|
/* stroke-width:2;stroke-dasharray:10.000000,9.865639;stroke-dashoffset:-198.656393;animation: dashdraw 4.932820s linear infinite;*/
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<pre id="diagram4" class="mermaid">
|
<pre id="diagram4" class="mermaid2">
|
||||||
---
|
|
||||||
config:
|
|
||||||
layout: elk
|
|
||||||
---
|
|
||||||
flowchart LR
|
flowchart LR
|
||||||
subgraph S2
|
A --> B
|
||||||
subgraph s1["APA"]
|
|
||||||
D{"Use the editor"}
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
D -- Mermaid js --> I{"fa:fa-code Text"}
|
|
||||||
D --> I
|
|
||||||
D --> I
|
|
||||||
|
|
||||||
end
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid">
|
<pre id="diagram4" class="mermaid">
|
||||||
|
flowchart LR
|
||||||
|
A e1@==> B
|
||||||
|
e1@{ animate: true}
|
||||||
|
</pre>
|
||||||
|
<pre id="diagram4" class="mermaid2">
|
||||||
|
flowchart LR
|
||||||
|
A e1@--> B
|
||||||
|
classDef animate stroke-width:2,stroke-dasharray:10\,8,stroke-dashoffset:-180,animation: edge-animation-frame 6s linear infinite, stroke-linecap: round
|
||||||
|
class e1 animate
|
||||||
|
</pre>
|
||||||
|
<h2>infinite</h2>
|
||||||
|
<pre id="diagram4" class="mermaid2">
|
||||||
|
flowchart LR
|
||||||
|
A e1@--> B
|
||||||
|
classDef animate stroke-dasharray: 9\,5,stroke-dashoffset: 900,animation: dash 25s linear infinite;
|
||||||
|
class e1 animate
|
||||||
|
</pre>
|
||||||
|
<h2>Mermaid - edge-animation-slow</h2>
|
||||||
|
<pre id="diagram4" class="mermaid">
|
||||||
|
flowchart LR
|
||||||
|
A e1@--> B
|
||||||
|
e1@{ animation: fast}
|
||||||
|
</pre>
|
||||||
|
<h2>Mermaid - edge-animation-fast</h2>
|
||||||
|
<pre id="diagram4" class="mermaid2">
|
||||||
|
flowchart LR
|
||||||
|
A e1@--> B
|
||||||
|
classDef animate stroke-dasharray: 1000,stroke-dashoffset: 1000,animation: dash 10s linear;
|
||||||
|
class e1 edge-animation-fast
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<pre id="diagram4" class="mermaid2">
|
||||||
|
|
||||||
|
info </pre
|
||||||
|
>
|
||||||
|
<pre id="diagram4" class="mermaid2">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
layout: elk
|
layout: elk
|
||||||
@ -131,7 +168,7 @@ config:
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid">
|
<pre id="diagram4" class="mermaid2">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
layout: elk
|
layout: elk
|
||||||
@ -144,7 +181,7 @@ config:
|
|||||||
D-->I
|
D-->I
|
||||||
D-->I
|
D-->I
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid">
|
<pre id="diagram4" class="mermaid2">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
layout: elk
|
layout: elk
|
||||||
@ -183,7 +220,7 @@ flowchart LR
|
|||||||
n8@{ shape: rect}
|
n8@{ shape: rect}
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid">
|
<pre id="diagram4" class="mermaid2">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
layout: elk
|
layout: elk
|
||||||
@ -199,7 +236,7 @@ flowchart LR
|
|||||||
|
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
<pre id="diagram4" class="mermaid">
|
<pre id="diagram4" class="mermaid2">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
layout: elk
|
layout: elk
|
||||||
@ -208,7 +245,7 @@ flowchart LR
|
|||||||
A{A} --> B & C
|
A{A} --> B & C
|
||||||
</pre
|
</pre
|
||||||
>
|
>
|
||||||
<pre id="diagram4" class="mermaid">
|
<pre id="diagram4" class="mermaid2">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
layout: elk
|
layout: elk
|
||||||
@ -220,7 +257,7 @@ flowchart LR
|
|||||||
end
|
end
|
||||||
</pre
|
</pre
|
||||||
>
|
>
|
||||||
<pre id="diagram4" class="mermaid">
|
<pre id="diagram4" class="mermaid2">
|
||||||
---
|
---
|
||||||
config:
|
config:
|
||||||
layout: elk
|
layout: elk
|
||||||
|
@ -24,7 +24,7 @@ import type {
|
|||||||
FlowLink,
|
FlowLink,
|
||||||
FlowVertexTypeParam,
|
FlowVertexTypeParam,
|
||||||
} from './types.js';
|
} from './types.js';
|
||||||
import type { NodeMetaData } from '../../types.js';
|
import type { NodeMetaData, EdgeMetaData } from '../../types.js';
|
||||||
|
|
||||||
const MERMAID_DOM_ID_PREFIX = 'flowchart-';
|
const MERMAID_DOM_ID_PREFIX = 'flowchart-';
|
||||||
let vertexCounter = 0;
|
let vertexCounter = 0;
|
||||||
@ -71,12 +71,38 @@ export const addVertex = function (
|
|||||||
classes: string[],
|
classes: string[],
|
||||||
dir: string,
|
dir: string,
|
||||||
props = {},
|
props = {},
|
||||||
shapeData: any
|
metadata: any
|
||||||
) {
|
) {
|
||||||
// console.log('addVertex', id, shapeData);
|
|
||||||
if (!id || id.trim().length === 0) {
|
if (!id || id.trim().length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Extract the metadata from the shapeData, the syntax for adding metadata for nodes and edges is the same
|
||||||
|
// so at this point we don't know if it's a node or an edge, but we can still extract the metadata
|
||||||
|
let doc;
|
||||||
|
if (metadata !== undefined) {
|
||||||
|
let yamlData;
|
||||||
|
// detect if shapeData contains a newline character
|
||||||
|
if (!metadata.includes('\n')) {
|
||||||
|
yamlData = '{\n' + metadata + '\n}';
|
||||||
|
} else {
|
||||||
|
yamlData = metadata + '\n';
|
||||||
|
}
|
||||||
|
doc = yaml.load(yamlData, { schema: yaml.JSON_SCHEMA }) as NodeMetaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this is an edge
|
||||||
|
const edge = edges.find((e) => e.id === id);
|
||||||
|
if (edge) {
|
||||||
|
const edgeDoc = doc as EdgeMetaData;
|
||||||
|
if (edgeDoc?.animate) {
|
||||||
|
edge.animate = edgeDoc.animate;
|
||||||
|
}
|
||||||
|
if (edgeDoc?.animation) {
|
||||||
|
edge.animation = edgeDoc.animation;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let txt;
|
let txt;
|
||||||
|
|
||||||
let vertex = vertices.get(id);
|
let vertex = vertices.get(id);
|
||||||
@ -128,19 +154,7 @@ export const addVertex = function (
|
|||||||
Object.assign(vertex.props, props);
|
Object.assign(vertex.props, props);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shapeData !== undefined) {
|
if (doc !== undefined) {
|
||||||
let yamlData;
|
|
||||||
// detect if shapeData contains a newline character
|
|
||||||
// console.log('shapeData', shapeData);
|
|
||||||
if (!shapeData.includes('\n')) {
|
|
||||||
// console.log('yamlData shapeData has no new lines', shapeData);
|
|
||||||
yamlData = '{\n' + shapeData + '\n}';
|
|
||||||
} else {
|
|
||||||
// console.log('yamlData shapeData has new lines', shapeData);
|
|
||||||
yamlData = shapeData + '\n';
|
|
||||||
}
|
|
||||||
// console.log('yamlData', yamlData);
|
|
||||||
const doc = yaml.load(yamlData, { schema: yaml.JSON_SCHEMA }) as NodeMetaData;
|
|
||||||
if (doc.shape) {
|
if (doc.shape) {
|
||||||
if (doc.shape !== doc.shape.toLowerCase() || doc.shape.includes('_')) {
|
if (doc.shape !== doc.shape.toLowerCase() || doc.shape.includes('_')) {
|
||||||
throw new Error(`No such shape: ${doc.shape}. Shape names should be lowercase.`);
|
throw new Error(`No such shape: ${doc.shape}. Shape names should be lowercase.`);
|
||||||
@ -187,11 +201,18 @@ export const addVertex = function (
|
|||||||
* Function called by parser when a link/edge definition has been found
|
* Function called by parser when a link/edge definition has been found
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export const addSingleLink = function (_start: string, _end: string, type: any) {
|
export const addSingleLink = function (_start: string, _end: string, type: any, id?: string) {
|
||||||
const start = _start;
|
const start = _start;
|
||||||
const end = _end;
|
const end = _end;
|
||||||
|
|
||||||
const edge: FlowEdge = { start: start, end: end, type: undefined, text: '', labelType: 'text' };
|
const edge: FlowEdge = {
|
||||||
|
start: start,
|
||||||
|
end: end,
|
||||||
|
type: undefined,
|
||||||
|
text: '',
|
||||||
|
labelType: 'text',
|
||||||
|
classes: [],
|
||||||
|
};
|
||||||
log.info('abc78 Got edge...', edge);
|
log.info('abc78 Got edge...', edge);
|
||||||
const linkTextObj = type.text;
|
const linkTextObj = type.text;
|
||||||
|
|
||||||
@ -210,6 +231,9 @@ export const addSingleLink = function (_start: string, _end: string, type: any)
|
|||||||
edge.stroke = type.stroke;
|
edge.stroke = type.stroke;
|
||||||
edge.length = type.length > 10 ? 10 : type.length;
|
edge.length = type.length > 10 ? 10 : type.length;
|
||||||
}
|
}
|
||||||
|
if (id) {
|
||||||
|
edge.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
if (edges.length < (config.maxEdges ?? 500)) {
|
if (edges.length < (config.maxEdges ?? 500)) {
|
||||||
log.info('Pushing edge...');
|
log.info('Pushing edge...');
|
||||||
@ -225,11 +249,17 @@ You have to call mermaid.initialize.`
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addLink = function (_start: string[], _end: string[], type: unknown) {
|
export const addLink = function (_start: string[], _end: string[], linkData: unknown) {
|
||||||
log.info('addLink', _start, _end, type);
|
const id =
|
||||||
|
linkData && typeof linkData === 'object' && 'id' in linkData
|
||||||
|
? linkData.id?.replace('@', '')
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
log.info('addLink', _start, _end, id);
|
||||||
|
|
||||||
for (const start of _start) {
|
for (const start of _start) {
|
||||||
for (const end of _end) {
|
for (const end of _end) {
|
||||||
addSingleLink(start, end, type);
|
addSingleLink(start, end, linkData, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -282,7 +312,13 @@ export const updateLink = function (positions: ('default' | number)[], style: st
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addClass = function (ids: string, style: string[]) {
|
export const addClass = function (ids: string, _style: string[]) {
|
||||||
|
const style = _style
|
||||||
|
.join()
|
||||||
|
.replace(/\\,/g, '§§§')
|
||||||
|
.replace(/,/g, ';')
|
||||||
|
.replace(/§§§/g, ',')
|
||||||
|
.split(';');
|
||||||
ids.split(',').forEach(function (id) {
|
ids.split(',').forEach(function (id) {
|
||||||
let classNode = classes.get(id);
|
let classNode = classes.get(id);
|
||||||
if (classNode === undefined) {
|
if (classNode === undefined) {
|
||||||
@ -337,6 +373,10 @@ export const setClass = function (ids: string, className: string) {
|
|||||||
if (vertex) {
|
if (vertex) {
|
||||||
vertex.classes.push(className);
|
vertex.classes.push(className);
|
||||||
}
|
}
|
||||||
|
const edge = edges.find((e) => e.id === id);
|
||||||
|
if (edge) {
|
||||||
|
edge.classes.push(className);
|
||||||
|
}
|
||||||
const subGraph = subGraphLookup.get(id);
|
const subGraph = subGraphLookup.get(id);
|
||||||
if (subGraph) {
|
if (subGraph) {
|
||||||
subGraph.classes.push(className);
|
subGraph.classes.push(className);
|
||||||
@ -997,7 +1037,7 @@ export const getData = () => {
|
|||||||
styles.push(...rawEdge.style);
|
styles.push(...rawEdge.style);
|
||||||
}
|
}
|
||||||
const edge: Edge = {
|
const edge: Edge = {
|
||||||
id: getEdgeId(rawEdge.start, rawEdge.end, { counter: index, prefix: 'L' }),
|
id: getEdgeId(rawEdge.start, rawEdge.end, { counter: index, prefix: 'L' }, rawEdge.id),
|
||||||
start: rawEdge.start,
|
start: rawEdge.start,
|
||||||
end: rawEdge.end,
|
end: rawEdge.end,
|
||||||
type: rawEdge.type ?? 'normal',
|
type: rawEdge.type ?? 'normal',
|
||||||
@ -1009,14 +1049,20 @@ export const getData = () => {
|
|||||||
rawEdge?.stroke === 'invisible'
|
rawEdge?.stroke === 'invisible'
|
||||||
? ''
|
? ''
|
||||||
: 'edge-thickness-normal edge-pattern-solid flowchart-link',
|
: 'edge-thickness-normal edge-pattern-solid flowchart-link',
|
||||||
arrowTypeStart: rawEdge?.stroke === 'invisible' ? 'none' : arrowTypeStart,
|
arrowTypeStart:
|
||||||
arrowTypeEnd: rawEdge?.stroke === 'invisible' ? 'none' : arrowTypeEnd,
|
rawEdge?.stroke === 'invisible' || rawEdge?.type === 'arrow_open' ? 'none' : arrowTypeStart,
|
||||||
|
arrowTypeEnd:
|
||||||
|
rawEdge?.stroke === 'invisible' || rawEdge?.type === 'arrow_open' ? 'none' : arrowTypeEnd,
|
||||||
arrowheadStyle: 'fill: #333',
|
arrowheadStyle: 'fill: #333',
|
||||||
|
cssCompiledStyles: getCompiledStyles(rawEdge.classes),
|
||||||
labelStyle: styles,
|
labelStyle: styles,
|
||||||
style: styles,
|
style: styles,
|
||||||
pattern: rawEdge.stroke,
|
pattern: rawEdge.stroke,
|
||||||
look: config.look,
|
look: config.look,
|
||||||
|
animate: rawEdge.animate,
|
||||||
|
animation: rawEdge.animation,
|
||||||
};
|
};
|
||||||
|
|
||||||
edges.push(edge);
|
edges.push(edge);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -39,6 +39,27 @@ const doubleEndedEdges = [
|
|||||||
{ edgeStart: '<==', edgeEnd: '==>', stroke: 'thick', type: 'double_arrow_point' },
|
{ edgeStart: '<==', edgeEnd: '==>', stroke: 'thick', type: 'double_arrow_point' },
|
||||||
{ edgeStart: '<-.', edgeEnd: '.->', stroke: 'dotted', type: 'double_arrow_point' },
|
{ edgeStart: '<-.', edgeEnd: '.->', stroke: 'dotted', type: 'double_arrow_point' },
|
||||||
];
|
];
|
||||||
|
const regularEdges = [
|
||||||
|
{ edgeStart: '--', edgeEnd: '--x', stroke: 'normal', type: 'arrow_cross' },
|
||||||
|
{ edgeStart: '==', edgeEnd: '==x', stroke: 'thick', type: 'arrow_cross' },
|
||||||
|
{ edgeStart: '-.', edgeEnd: '.-x', stroke: 'dotted', type: 'arrow_cross' },
|
||||||
|
{ edgeStart: '--', edgeEnd: '--o', stroke: 'normal', type: 'arrow_circle' },
|
||||||
|
{ edgeStart: '==', edgeEnd: '==o', stroke: 'thick', type: 'arrow_circle' },
|
||||||
|
{ edgeStart: '-.', edgeEnd: '.-o', stroke: 'dotted', type: 'arrow_circle' },
|
||||||
|
{ edgeStart: '--', edgeEnd: '-->', stroke: 'normal', type: 'arrow_point' },
|
||||||
|
{ edgeStart: '==', edgeEnd: '==>', stroke: 'thick', type: 'arrow_point' },
|
||||||
|
{ edgeStart: '-.', edgeEnd: '.->', stroke: 'dotted', type: 'arrow_point' },
|
||||||
|
|
||||||
|
{ edgeStart: '--', edgeEnd: '----x', stroke: 'normal', type: 'arrow_cross' },
|
||||||
|
{ edgeStart: '==', edgeEnd: '====x', stroke: 'thick', type: 'arrow_cross' },
|
||||||
|
{ edgeStart: '-.', edgeEnd: '...-x', stroke: 'dotted', type: 'arrow_cross' },
|
||||||
|
{ edgeStart: '--', edgeEnd: '----o', stroke: 'normal', type: 'arrow_circle' },
|
||||||
|
{ edgeStart: '==', edgeEnd: '====o', stroke: 'thick', type: 'arrow_circle' },
|
||||||
|
{ edgeStart: '-.', edgeEnd: '...-o', stroke: 'dotted', type: 'arrow_circle' },
|
||||||
|
{ edgeStart: '--', edgeEnd: '---->', stroke: 'normal', type: 'arrow_point' },
|
||||||
|
{ edgeStart: '==', edgeEnd: '====>', stroke: 'thick', type: 'arrow_point' },
|
||||||
|
{ edgeStart: '-.', edgeEnd: '...->', stroke: 'dotted', type: 'arrow_point' },
|
||||||
|
];
|
||||||
|
|
||||||
describe('[Edges] when parsing', () => {
|
describe('[Edges] when parsing', () => {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
@ -67,6 +88,74 @@ describe('[Edges] when parsing', () => {
|
|||||||
expect(edges[0].type).toBe('arrow_circle');
|
expect(edges[0].type).toBe('arrow_circle');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('edges with ids', function () {
|
||||||
|
describe('open ended edges with ids and labels', function () {
|
||||||
|
regularEdges.forEach((edgeType) => {
|
||||||
|
it(`should handle ${edgeType.stroke} ${edgeType.type} with no text`, function () {
|
||||||
|
const res = flow.parser.parse(
|
||||||
|
`flowchart TD;\nA e1@${edgeType.edgeStart}${edgeType.edgeEnd} B;`
|
||||||
|
);
|
||||||
|
const vert = flow.parser.yy.getVertices();
|
||||||
|
const edges = flow.parser.yy.getEdges();
|
||||||
|
expect(vert.get('A').id).toBe('A');
|
||||||
|
expect(vert.get('B').id).toBe('B');
|
||||||
|
expect(edges.length).toBe(1);
|
||||||
|
expect(edges[0].id).toBe('e1');
|
||||||
|
expect(edges[0].start).toBe('A');
|
||||||
|
expect(edges[0].end).toBe('B');
|
||||||
|
expect(edges[0].type).toBe(`${edgeType.type}`);
|
||||||
|
expect(edges[0].text).toBe('');
|
||||||
|
expect(edges[0].stroke).toBe(`${edgeType.stroke}`);
|
||||||
|
});
|
||||||
|
it(`should handle ${edgeType.stroke} ${edgeType.type} with text`, function () {
|
||||||
|
const res = flow.parser.parse(
|
||||||
|
`flowchart TD;\nA e1@${edgeType.edgeStart}${edgeType.edgeEnd} B;`
|
||||||
|
);
|
||||||
|
const vert = flow.parser.yy.getVertices();
|
||||||
|
const edges = flow.parser.yy.getEdges();
|
||||||
|
expect(vert.get('A').id).toBe('A');
|
||||||
|
expect(vert.get('B').id).toBe('B');
|
||||||
|
expect(edges.length).toBe(1);
|
||||||
|
expect(edges[0].id).toBe('e1');
|
||||||
|
expect(edges[0].start).toBe('A');
|
||||||
|
expect(edges[0].end).toBe('B');
|
||||||
|
expect(edges[0].type).toBe(`${edgeType.type}`);
|
||||||
|
expect(edges[0].text).toBe('');
|
||||||
|
expect(edges[0].stroke).toBe(`${edgeType.stroke}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('should handle normal edges where you also have a node with metadata', function () {
|
||||||
|
const res = flow.parser.parse(`flowchart LR
|
||||||
|
A id1@-->B
|
||||||
|
A@{ shape: 'rect' }
|
||||||
|
`);
|
||||||
|
const edges = flow.parser.yy.getEdges();
|
||||||
|
|
||||||
|
expect(edges[0].id).toBe('id1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('double ended edges with ids and labels', function () {
|
||||||
|
doubleEndedEdges.forEach((edgeType) => {
|
||||||
|
it(`should handle ${edgeType.stroke} ${edgeType.type} with text`, function () {
|
||||||
|
const res = flow.parser.parse(
|
||||||
|
`flowchart TD;\nA e1@${edgeType.edgeStart} label ${edgeType.edgeEnd} B;`
|
||||||
|
);
|
||||||
|
const vert = flow.parser.yy.getVertices();
|
||||||
|
const edges = flow.parser.yy.getEdges();
|
||||||
|
expect(vert.get('A').id).toBe('A');
|
||||||
|
expect(vert.get('B').id).toBe('B');
|
||||||
|
expect(edges.length).toBe(1);
|
||||||
|
expect(edges[0].id).toBe('e1');
|
||||||
|
expect(edges[0].start).toBe('A');
|
||||||
|
expect(edges[0].end).toBe('B');
|
||||||
|
expect(edges[0].type).toBe(`${edgeType.type}`);
|
||||||
|
expect(edges[0].text).toBe('label');
|
||||||
|
expect(edges[0].stroke).toBe(`${edgeType.stroke}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('edges', function () {
|
describe('edges', function () {
|
||||||
doubleEndedEdges.forEach((edgeType) => {
|
doubleEndedEdges.forEach((edgeType) => {
|
||||||
it(`should handle ${edgeType.stroke} ${edgeType.type} with no text`, function () {
|
it(`should handle ${edgeType.stroke} ${edgeType.type} with no text`, function () {
|
||||||
|
@ -141,6 +141,7 @@ that id.
|
|||||||
.*direction\s+RL[^\n]* return 'direction_rl';
|
.*direction\s+RL[^\n]* return 'direction_rl';
|
||||||
.*direction\s+LR[^\n]* return 'direction_lr';
|
.*direction\s+LR[^\n]* return 'direction_lr';
|
||||||
|
|
||||||
|
[^\s]+\@(?=[^\{]) { return 'LINK_ID'; }
|
||||||
[0-9]+ return 'NUM';
|
[0-9]+ return 'NUM';
|
||||||
\# return 'BRKT';
|
\# return 'BRKT';
|
||||||
":::" return 'STYLE_SEPARATOR';
|
":::" return 'STYLE_SEPARATOR';
|
||||||
@ -201,7 +202,9 @@ that id.
|
|||||||
"*" return 'MULT';
|
"*" return 'MULT';
|
||||||
"#" return 'BRKT';
|
"#" return 'BRKT';
|
||||||
"&" return 'AMP';
|
"&" return 'AMP';
|
||||||
([A-Za-z0-9!"\#$%&'*+\.`?\\_\/]|\-(?=[^\>\-\.])|=(?!=))+ return 'NODE_STRING';
|
([A-Za-z0-9!"\#$%&'*+\.`?\\_\/]|\-(?=[^\>\-\.])|=(?!=))+ {
|
||||||
|
return 'NODE_STRING';
|
||||||
|
}
|
||||||
"-" return 'MINUS'
|
"-" return 'MINUS'
|
||||||
[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|
|
[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|
|
||||||
[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|
|
[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|
|
||||||
@ -361,7 +364,7 @@ spaceList
|
|||||||
|
|
||||||
statement
|
statement
|
||||||
: vertexStatement separator
|
: vertexStatement separator
|
||||||
{ /* console.warn('finat vs', $vertexStatement.nodes); */ $$=$vertexStatement.nodes}
|
{ $$=$vertexStatement.nodes}
|
||||||
| styleStatement separator
|
| styleStatement separator
|
||||||
{$$=[];}
|
{$$=[];}
|
||||||
| linkStyleStatement separator
|
| linkStyleStatement separator
|
||||||
@ -472,6 +475,8 @@ link: linkStatement arrowText
|
|||||||
{$$ = $linkStatement;}
|
{$$ = $linkStatement;}
|
||||||
| START_LINK edgeText LINK
|
| START_LINK edgeText LINK
|
||||||
{var inf = yy.destructLink($LINK, $START_LINK); $$ = {"type":inf.type,"stroke":inf.stroke,"length":inf.length,"text":$edgeText};}
|
{var inf = yy.destructLink($LINK, $START_LINK); $$ = {"type":inf.type,"stroke":inf.stroke,"length":inf.length,"text":$edgeText};}
|
||||||
|
| LINK_ID START_LINK edgeText LINK
|
||||||
|
{var inf = yy.destructLink($LINK, $START_LINK); $$ = {"type":inf.type,"stroke":inf.stroke,"length":inf.length,"text":$edgeText, "id": $LINK_ID};}
|
||||||
;
|
;
|
||||||
|
|
||||||
edgeText: edgeTextToken
|
edgeText: edgeTextToken
|
||||||
@ -487,6 +492,8 @@ edgeText: edgeTextToken
|
|||||||
|
|
||||||
linkStatement: LINK
|
linkStatement: LINK
|
||||||
{var inf = yy.destructLink($LINK);$$ = {"type":inf.type,"stroke":inf.stroke,"length":inf.length};}
|
{var inf = yy.destructLink($LINK);$$ = {"type":inf.type,"stroke":inf.stroke,"length":inf.length};}
|
||||||
|
| LINK_ID LINK
|
||||||
|
{var inf = yy.destructLink($LINK);$$ = {"type":inf.type,"stroke":inf.stroke,"length":inf.length, "id": $LINK_ID};}
|
||||||
;
|
;
|
||||||
|
|
||||||
arrowText:
|
arrowText:
|
||||||
|
@ -62,6 +62,10 @@ export interface FlowEdge {
|
|||||||
length?: number;
|
length?: number;
|
||||||
text: string;
|
text: string;
|
||||||
labelType: 'text';
|
labelType: 'text';
|
||||||
|
classes: string[];
|
||||||
|
id?: string;
|
||||||
|
animation?: 'fast' | 'slow';
|
||||||
|
animate?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FlowClass {
|
export interface FlowClass {
|
||||||
|
@ -9,6 +9,7 @@ import { curveBasis, line, select } from 'd3';
|
|||||||
import rough from 'roughjs';
|
import rough from 'roughjs';
|
||||||
import createLabel from './createLabel.js';
|
import createLabel from './createLabel.js';
|
||||||
import { addEdgeMarkers } from './edgeMarker.ts';
|
import { addEdgeMarkers } from './edgeMarker.ts';
|
||||||
|
import { isLabelStyle } from './shapes/handDrawnShapeStyles.js';
|
||||||
|
|
||||||
const edgeLabels = new Map();
|
const edgeLabels = new Map();
|
||||||
const terminalLabels = new Map();
|
const terminalLabels = new Map();
|
||||||
@ -429,6 +430,14 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
|
|||||||
const tail = startNode;
|
const tail = startNode;
|
||||||
var head = endNode;
|
var head = endNode;
|
||||||
|
|
||||||
|
const edgeClassStyles = [];
|
||||||
|
for (const key in edge.cssCompiledStyles) {
|
||||||
|
if (isLabelStyle(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
edgeClassStyles.push(edge.cssCompiledStyles[key]);
|
||||||
|
}
|
||||||
|
|
||||||
if (head.intersect && tail.intersect) {
|
if (head.intersect && tail.intersect) {
|
||||||
points = points.slice(1, edge.points.length - 1);
|
points = points.slice(1, edge.points.length - 1);
|
||||||
points.unshift(tail.intersect(points[0]));
|
points.unshift(tail.intersect(points[0]));
|
||||||
@ -521,12 +530,27 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
|
|||||||
svgPath.attr('d', d);
|
svgPath.attr('d', d);
|
||||||
elem.node().appendChild(svgPath.node());
|
elem.node().appendChild(svgPath.node());
|
||||||
} else {
|
} else {
|
||||||
|
const stylesFromClasses = edgeClassStyles.join(';');
|
||||||
|
const styles = edge.edgeStyles ? edgeStyles.reduce((acc, style) => acc + ';' + style, '') : '';
|
||||||
|
let animationClass = '';
|
||||||
|
if (edge.animate) {
|
||||||
|
animationClass = ' edge-animation-fast';
|
||||||
|
}
|
||||||
|
if (edge.animation) {
|
||||||
|
animationClass = ' edge-animation-' + edge.animation;
|
||||||
|
}
|
||||||
svgPath = elem
|
svgPath = elem
|
||||||
.append('path')
|
.append('path')
|
||||||
.attr('d', linePath)
|
.attr('d', linePath)
|
||||||
.attr('id', edge.id)
|
.attr('id', edge.id)
|
||||||
.attr('class', ' ' + strokeClasses + (edge.classes ? ' ' + edge.classes : ''))
|
.attr(
|
||||||
.attr('style', edgeStyles ? edgeStyles.reduce((acc, style) => acc + ';' + style, '') : '');
|
'class',
|
||||||
|
' ' +
|
||||||
|
strokeClasses +
|
||||||
|
(edge.classes ? ' ' + edge.classes : '') +
|
||||||
|
(animationClass ? animationClass : '')
|
||||||
|
)
|
||||||
|
.attr('style', stylesFromClasses + ';' + styles);
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEBUG code, DO NOT REMOVE
|
// DEBUG code, DO NOT REMOVE
|
||||||
|
@ -32,17 +32,8 @@ export const styles2Map = (styles: string[]) => {
|
|||||||
});
|
});
|
||||||
return styleMap;
|
return styleMap;
|
||||||
};
|
};
|
||||||
|
export const isLabelStyle = (key: string) => {
|
||||||
export const styles2String = (node: Node) => {
|
return (
|
||||||
const { stylesArray } = compileStyles(node);
|
|
||||||
const labelStyles: string[] = [];
|
|
||||||
const nodeStyles: string[] = [];
|
|
||||||
const borderStyles: string[] = [];
|
|
||||||
const backgroundStyles: string[] = [];
|
|
||||||
|
|
||||||
stylesArray.forEach((style) => {
|
|
||||||
const key = style[0];
|
|
||||||
if (
|
|
||||||
key === 'color' ||
|
key === 'color' ||
|
||||||
key === 'font-size' ||
|
key === 'font-size' ||
|
||||||
key === 'font-family' ||
|
key === 'font-family' ||
|
||||||
@ -61,7 +52,18 @@ export const styles2String = (node: Node) => {
|
|||||||
key === 'word-break' ||
|
key === 'word-break' ||
|
||||||
key === 'overflow-wrap' ||
|
key === 'overflow-wrap' ||
|
||||||
key === 'hyphens'
|
key === 'hyphens'
|
||||||
) {
|
);
|
||||||
|
};
|
||||||
|
export const styles2String = (node: Node) => {
|
||||||
|
const { stylesArray } = compileStyles(node);
|
||||||
|
const labelStyles: string[] = [];
|
||||||
|
const nodeStyles: string[] = [];
|
||||||
|
const borderStyles: string[] = [];
|
||||||
|
const backgroundStyles: string[] = [];
|
||||||
|
|
||||||
|
stylesArray.forEach((style) => {
|
||||||
|
const key = style[0];
|
||||||
|
if (isLabelStyle(key)) {
|
||||||
labelStyles.push(style.join(':') + ' !important');
|
labelStyles.push(style.join(':') + ' !important');
|
||||||
} else {
|
} else {
|
||||||
nodeStyles.push(style.join(':') + ' !important');
|
nodeStyles.push(style.join(':') + ' !important');
|
||||||
|
@ -101,6 +101,7 @@ export interface Edge {
|
|||||||
arrowheadStyle?: string;
|
arrowheadStyle?: string;
|
||||||
arrowTypeEnd?: string;
|
arrowTypeEnd?: string;
|
||||||
arrowTypeStart?: string;
|
arrowTypeStart?: string;
|
||||||
|
cssCompiledStyles?: string[];
|
||||||
// Flowchart specific properties
|
// Flowchart specific properties
|
||||||
defaultInterpolate?: string;
|
defaultInterpolate?: string;
|
||||||
end?: string;
|
end?: string;
|
||||||
|
@ -27,7 +27,28 @@ const getStyles = (
|
|||||||
font-size: ${options.fontSize};
|
font-size: ${options.fontSize};
|
||||||
fill: ${options.textColor}
|
fill: ${options.textColor}
|
||||||
}
|
}
|
||||||
|
@keyframes edge-animation-frame {
|
||||||
|
from {
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes dash {
|
||||||
|
to {
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
& .edge-animation-slow {
|
||||||
|
stroke-dasharray: 9,5 !important;
|
||||||
|
stroke-dashoffset: 900;
|
||||||
|
animation: dash 50s linear infinite;
|
||||||
|
stroke-linecap: round;
|
||||||
|
}
|
||||||
|
& .edge-animation-fast {
|
||||||
|
stroke-dasharray: 9,5 !important;
|
||||||
|
stroke-dashoffset: 900;
|
||||||
|
animation: dash 20s linear infinite;
|
||||||
|
stroke-linecap: round;
|
||||||
|
}
|
||||||
/* Classes common for multiple diagrams */
|
/* Classes common for multiple diagrams */
|
||||||
|
|
||||||
& .error-icon {
|
& .error-icon {
|
||||||
|
@ -12,6 +12,11 @@ export interface NodeMetaData {
|
|||||||
assigned?: string;
|
assigned?: string;
|
||||||
ticket?: string;
|
ticket?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface EdgeMetaData {
|
||||||
|
animation?: 'fast' | 'slow';
|
||||||
|
animate?: boolean;
|
||||||
|
}
|
||||||
import type { MermaidConfig } from './config.type.js';
|
import type { MermaidConfig } from './config.type.js';
|
||||||
|
|
||||||
export interface Point {
|
export interface Point {
|
||||||
|
@ -937,8 +937,12 @@ export const getEdgeId = (
|
|||||||
counter?: number;
|
counter?: number;
|
||||||
prefix?: string;
|
prefix?: string;
|
||||||
suffix?: string;
|
suffix?: string;
|
||||||
}
|
},
|
||||||
|
id?: string
|
||||||
) => {
|
) => {
|
||||||
|
if (id) {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
return `${prefix ? `${prefix}_` : ''}${from}_${to}_${counter}${suffix ? `_${suffix}` : ''}`;
|
return `${prefix ? `${prefix}_` : ''}${from}_${to}_${counter}${suffix ? `_${suffix}` : ''}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user