mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-08-15 06:19:24 +02:00
Merge pull request #4825 from chadfawcett/bug/1871_fix_duplicate_marker_ids
Give markers unique id's per graph
This commit is contained in:
10
cypress/integration/rendering/marker_unique_id.spec.js
Normal file
10
cypress/integration/rendering/marker_unique_id.spec.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import { urlSnapshotTest } from '../../helpers/util.ts';
|
||||
|
||||
describe('Marker Unique IDs Per Diagram', () => {
|
||||
it('should render a blue arrow tip in second digram', () => {
|
||||
urlSnapshotTest('http://localhost:9000/marker_unique_id.html', {
|
||||
logLevel: 1,
|
||||
flowchart: { htmlLabels: false },
|
||||
});
|
||||
});
|
||||
});
|
52
cypress/platform/marker_unique_id.html
Normal file
52
cypress/platform/marker_unique_id.html
Normal file
@@ -0,0 +1,52 @@
|
||||
<html>
|
||||
<head> </head>
|
||||
<body>
|
||||
<h1>Example</h1>
|
||||
<pre class="mermaid">
|
||||
%%{init:{"theme":"base", "themeVariables": {"lineColor":"red"}}}%%
|
||||
flowchart LR
|
||||
subgraph red
|
||||
A --> B
|
||||
end
|
||||
</pre>
|
||||
<pre class="mermaid">
|
||||
%%{init:{"theme":"base", "themeVariables": {"lineColor":"blue"}}}%%
|
||||
flowchart LR
|
||||
subgraph black
|
||||
A --> B
|
||||
end
|
||||
</pre>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
config:
|
||||
theme: base
|
||||
themeVariables:
|
||||
lineColor: yellow
|
||||
---
|
||||
flowchart LR
|
||||
subgraph red
|
||||
A --> B
|
||||
end
|
||||
</pre>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
config:
|
||||
theme: base
|
||||
themeVariables:
|
||||
lineColor: green
|
||||
---
|
||||
flowchart LR
|
||||
subgraph black
|
||||
A --> B
|
||||
end
|
||||
</pre>
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
mermaid.initialize({ startOnLoad: true, logLevel: 0 });
|
||||
|
||||
if (window.Cypress) {
|
||||
window.rendered = true;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@@ -369,7 +369,7 @@ const cutPathAtIntersect = (_points, boundryNode) => {
|
||||
return points;
|
||||
};
|
||||
|
||||
export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph) {
|
||||
export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph, id) {
|
||||
let points = edge.points;
|
||||
let pointsHasChanged = false;
|
||||
const tail = graph.node(e.v);
|
||||
@@ -508,61 +508,103 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph
|
||||
|
||||
switch (edge.arrowTypeStart) {
|
||||
case 'arrow_cross':
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-crossStart' + ')');
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + id + '_' + diagramType + '-crossStart' + ')'
|
||||
);
|
||||
break;
|
||||
case 'arrow_point':
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-pointStart' + ')');
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + id + '_' + diagramType + '-pointStart' + ')'
|
||||
);
|
||||
break;
|
||||
case 'arrow_barb':
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-barbStart' + ')');
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + id + '_' + diagramType + '-barbStart' + ')'
|
||||
);
|
||||
break;
|
||||
case 'arrow_circle':
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-circleStart' + ')');
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + id + '_' + diagramType + '-circleStart' + ')'
|
||||
);
|
||||
break;
|
||||
case 'aggregation':
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-aggregationStart' + ')');
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + id + '_' + diagramType + '-aggregationStart' + ')'
|
||||
);
|
||||
break;
|
||||
case 'extension':
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-extensionStart' + ')');
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + id + '_' + diagramType + '-extensionStart' + ')'
|
||||
);
|
||||
break;
|
||||
case 'composition':
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-compositionStart' + ')');
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + id + '_' + diagramType + '-compositionStart' + ')'
|
||||
);
|
||||
break;
|
||||
case 'dependency':
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-dependencyStart' + ')');
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + id + '_' + diagramType + '-dependencyStart' + ')'
|
||||
);
|
||||
break;
|
||||
case 'lollipop':
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + diagramType + '-lollipopStart' + ')');
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + id + '_' + diagramType + '-lollipopStart' + ')'
|
||||
);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
switch (edge.arrowTypeEnd) {
|
||||
case 'arrow_cross':
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-crossEnd' + ')');
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + id + '_' + diagramType + '-crossEnd' + ')');
|
||||
break;
|
||||
case 'arrow_point':
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-pointEnd' + ')');
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + id + '_' + diagramType + '-pointEnd' + ')');
|
||||
break;
|
||||
case 'arrow_barb':
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-barbEnd' + ')');
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + id + '_' + diagramType + '-barbEnd' + ')');
|
||||
break;
|
||||
case 'arrow_circle':
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-circleEnd' + ')');
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + id + '_' + diagramType + '-circleEnd' + ')');
|
||||
break;
|
||||
case 'aggregation':
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-aggregationEnd' + ')');
|
||||
svgPath.attr(
|
||||
'marker-end',
|
||||
'url(' + url + '#' + id + '_' + diagramType + '-aggregationEnd' + ')'
|
||||
);
|
||||
break;
|
||||
case 'extension':
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-extensionEnd' + ')');
|
||||
svgPath.attr(
|
||||
'marker-end',
|
||||
'url(' + url + '#' + id + '_' + diagramType + '-extensionEnd' + ')'
|
||||
);
|
||||
break;
|
||||
case 'composition':
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-compositionEnd' + ')');
|
||||
svgPath.attr(
|
||||
'marker-end',
|
||||
'url(' + url + '#' + id + '_' + diagramType + '-compositionEnd' + ')'
|
||||
);
|
||||
break;
|
||||
case 'dependency':
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-dependencyEnd' + ')');
|
||||
svgPath.attr(
|
||||
'marker-end',
|
||||
'url(' + url + '#' + id + '_' + diagramType + '-dependencyEnd' + ')'
|
||||
);
|
||||
break;
|
||||
case 'lollipop':
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + diagramType + '-lollipopEnd' + ')');
|
||||
svgPath.attr(
|
||||
'marker-end',
|
||||
'url(' + url + '#' + id + '_' + diagramType + '-lollipopEnd' + ')'
|
||||
);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@ import { insertCluster, clear as clearClusters } from './clusters.js';
|
||||
import { insertEdgeLabel, positionEdgeLabel, insertEdge, clear as clearEdges } from './edges.js';
|
||||
import { log } from '../logger.js';
|
||||
|
||||
const recursiveRender = async (_elem, graph, diagramtype, parentCluster) => {
|
||||
const recursiveRender = async (_elem, graph, diagramtype, id, parentCluster) => {
|
||||
log.info('Graph in recursive render: XXX', graphlibJson.write(graph), parentCluster);
|
||||
const dir = graph.graph().rankdir;
|
||||
log.trace('Dir in recursive render - dir:', dir);
|
||||
@@ -52,7 +52,7 @@ const recursiveRender = async (_elem, graph, diagramtype, parentCluster) => {
|
||||
if (node && node.clusterNode) {
|
||||
// const children = graph.children(v);
|
||||
log.info('Cluster identified', v, node.width, graph.node(v));
|
||||
const o = await recursiveRender(nodes, node.graph, diagramtype, graph.node(v));
|
||||
const o = await recursiveRender(nodes, node.graph, diagramtype, id, graph.node(v));
|
||||
const newEl = o.elem;
|
||||
updateNodeBounds(node, newEl);
|
||||
node.diff = o.diff || 0;
|
||||
@@ -134,7 +134,7 @@ const recursiveRender = async (_elem, graph, diagramtype, parentCluster) => {
|
||||
const edge = graph.edge(e);
|
||||
log.info('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(edge), edge);
|
||||
|
||||
const paths = insertEdge(edgePaths, e, edge, clusterDb, diagramtype, graph);
|
||||
const paths = insertEdge(edgePaths, e, edge, clusterDb, diagramtype, graph, id);
|
||||
positionEdgeLabel(edge, paths);
|
||||
});
|
||||
|
||||
@@ -159,7 +159,7 @@ export const render = async (elem, graph, markers, diagramtype, id) => {
|
||||
adjustClustersAndEdges(graph);
|
||||
log.warn('Graph after:', JSON.stringify(graphlibJson.write(graph)));
|
||||
// log.warn('Graph ever after:', graphlibJson.write(graph.node('A').graph));
|
||||
await recursiveRender(elem, graph, diagramtype);
|
||||
await recursiveRender(elem, graph, diagramtype, id);
|
||||
};
|
||||
|
||||
// const shapeDefinitions = {};
|
||||
|
@@ -14,7 +14,7 @@ const extension = (elem, type, id) => {
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', type + '-extensionStart')
|
||||
.attr('id', id + '_' + type + '-extensionStart')
|
||||
.attr('class', 'marker extension ' + type)
|
||||
.attr('refX', 18)
|
||||
.attr('refY', 7)
|
||||
@@ -27,7 +27,7 @@ const extension = (elem, type, id) => {
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', type + '-extensionEnd')
|
||||
.attr('id', id + '_' + type + '-extensionEnd')
|
||||
.attr('class', 'marker extension ' + type)
|
||||
.attr('refX', 1)
|
||||
.attr('refY', 7)
|
||||
@@ -38,11 +38,11 @@ const extension = (elem, type, id) => {
|
||||
.attr('d', 'M 1,1 V 13 L18,7 Z'); // this is actual shape for arrowhead
|
||||
};
|
||||
|
||||
const composition = (elem, type) => {
|
||||
const composition = (elem, type, id) => {
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', type + '-compositionStart')
|
||||
.attr('id', id + '_' + type + '-compositionStart')
|
||||
.attr('class', 'marker composition ' + type)
|
||||
.attr('refX', 18)
|
||||
.attr('refY', 7)
|
||||
@@ -55,7 +55,7 @@ const composition = (elem, type) => {
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', type + '-compositionEnd')
|
||||
.attr('id', id + '_' + type + '-compositionEnd')
|
||||
.attr('class', 'marker composition ' + type)
|
||||
.attr('refX', 1)
|
||||
.attr('refY', 7)
|
||||
@@ -65,11 +65,11 @@ const composition = (elem, type) => {
|
||||
.append('path')
|
||||
.attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z');
|
||||
};
|
||||
const aggregation = (elem, type) => {
|
||||
const aggregation = (elem, type, id) => {
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', type + '-aggregationStart')
|
||||
.attr('id', id + '_' + type + '-aggregationStart')
|
||||
.attr('class', 'marker aggregation ' + type)
|
||||
.attr('refX', 18)
|
||||
.attr('refY', 7)
|
||||
@@ -82,7 +82,7 @@ const aggregation = (elem, type) => {
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', type + '-aggregationEnd')
|
||||
.attr('id', id + '_' + type + '-aggregationEnd')
|
||||
.attr('class', 'marker aggregation ' + type)
|
||||
.attr('refX', 1)
|
||||
.attr('refY', 7)
|
||||
@@ -92,11 +92,11 @@ const aggregation = (elem, type) => {
|
||||
.append('path')
|
||||
.attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z');
|
||||
};
|
||||
const dependency = (elem, type) => {
|
||||
const dependency = (elem, type, id) => {
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', type + '-dependencyStart')
|
||||
.attr('id', id + '_' + type + '-dependencyStart')
|
||||
.attr('class', 'marker dependency ' + type)
|
||||
.attr('refX', 6)
|
||||
.attr('refY', 7)
|
||||
@@ -109,7 +109,7 @@ const dependency = (elem, type) => {
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', type + '-dependencyEnd')
|
||||
.attr('id', id + '_' + type + '-dependencyEnd')
|
||||
.attr('class', 'marker dependency ' + type)
|
||||
.attr('refX', 13)
|
||||
.attr('refY', 7)
|
||||
@@ -119,11 +119,11 @@ const dependency = (elem, type) => {
|
||||
.append('path')
|
||||
.attr('d', 'M 18,7 L9,13 L14,7 L9,1 Z');
|
||||
};
|
||||
const lollipop = (elem, type) => {
|
||||
const lollipop = (elem, type, id) => {
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', type + '-lollipopStart')
|
||||
.attr('id', id + '_' + type + '-lollipopStart')
|
||||
.attr('class', 'marker lollipop ' + type)
|
||||
.attr('refX', 13)
|
||||
.attr('refY', 7)
|
||||
@@ -140,7 +140,7 @@ const lollipop = (elem, type) => {
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', type + '-lollipopEnd')
|
||||
.attr('id', id + '_' + type + '-lollipopEnd')
|
||||
.attr('class', 'marker lollipop ' + type)
|
||||
.attr('refX', 1)
|
||||
.attr('refY', 7)
|
||||
@@ -154,10 +154,10 @@ const lollipop = (elem, type) => {
|
||||
.attr('cy', 7)
|
||||
.attr('r', 6);
|
||||
};
|
||||
const point = (elem, type) => {
|
||||
const point = (elem, type, id) => {
|
||||
elem
|
||||
.append('marker')
|
||||
.attr('id', type + '-pointEnd')
|
||||
.attr('id', id + '_' + type + '-pointEnd')
|
||||
.attr('class', 'marker ' + type)
|
||||
.attr('viewBox', '0 0 10 10')
|
||||
.attr('refX', 6)
|
||||
@@ -173,7 +173,7 @@ const point = (elem, type) => {
|
||||
.style('stroke-dasharray', '1,0');
|
||||
elem
|
||||
.append('marker')
|
||||
.attr('id', type + '-pointStart')
|
||||
.attr('id', id + '_' + type + '-pointStart')
|
||||
.attr('class', 'marker ' + type)
|
||||
.attr('viewBox', '0 0 10 10')
|
||||
.attr('refX', 4.5)
|
||||
@@ -188,10 +188,10 @@ const point = (elem, type) => {
|
||||
.style('stroke-width', 1)
|
||||
.style('stroke-dasharray', '1,0');
|
||||
};
|
||||
const circle = (elem, type) => {
|
||||
const circle = (elem, type, id) => {
|
||||
elem
|
||||
.append('marker')
|
||||
.attr('id', type + '-circleEnd')
|
||||
.attr('id', id + '_' + type + '-circleEnd')
|
||||
.attr('class', 'marker ' + type)
|
||||
.attr('viewBox', '0 0 10 10')
|
||||
.attr('refX', 11)
|
||||
@@ -210,7 +210,7 @@ const circle = (elem, type) => {
|
||||
|
||||
elem
|
||||
.append('marker')
|
||||
.attr('id', type + '-circleStart')
|
||||
.attr('id', id + '_' + type + '-circleStart')
|
||||
.attr('class', 'marker ' + type)
|
||||
.attr('viewBox', '0 0 10 10')
|
||||
.attr('refX', -1)
|
||||
@@ -227,10 +227,10 @@ const circle = (elem, type) => {
|
||||
.style('stroke-width', 1)
|
||||
.style('stroke-dasharray', '1,0');
|
||||
};
|
||||
const cross = (elem, type) => {
|
||||
const cross = (elem, type, id) => {
|
||||
elem
|
||||
.append('marker')
|
||||
.attr('id', type + '-crossEnd')
|
||||
.attr('id', id + '_' + type + '-crossEnd')
|
||||
.attr('class', 'marker cross ' + type)
|
||||
.attr('viewBox', '0 0 11 11')
|
||||
.attr('refX', 12)
|
||||
@@ -248,7 +248,7 @@ const cross = (elem, type) => {
|
||||
|
||||
elem
|
||||
.append('marker')
|
||||
.attr('id', type + '-crossStart')
|
||||
.attr('id', id + '_' + type + '-crossStart')
|
||||
.attr('class', 'marker cross ' + type)
|
||||
.attr('viewBox', '0 0 11 11')
|
||||
.attr('refX', -1)
|
||||
@@ -264,11 +264,11 @@ const cross = (elem, type) => {
|
||||
.style('stroke-width', 2)
|
||||
.style('stroke-dasharray', '1,0');
|
||||
};
|
||||
const barb = (elem, type) => {
|
||||
const barb = (elem, type, id) => {
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', type + '-barbEnd')
|
||||
.attr('id', id + '_' + type + '-barbEnd')
|
||||
.attr('refX', 19)
|
||||
.attr('refY', 7)
|
||||
.attr('markerWidth', 20)
|
||||
|
Reference in New Issue
Block a user