Skip to content

Commit

Permalink
feat: render markers as part of djs-visual
Browse files Browse the repository at this point in the history
  • Loading branch information
marstamm committed May 27, 2024
1 parent 07bf015 commit d616a34
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 58 deletions.
2 changes: 1 addition & 1 deletion lib/BaseViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ BaseViewer.prototype.saveSVG = async function saveSVG() {
const canvas = this.get('canvas');

const contentNode = canvas.getActiveLayer(),
defsNode = domQuery('defs', canvas._svg);
defsNode = domQuery(':scope > defs', canvas._svg);

const contents = innerSVG(contentNode),
defs = defsNode ? '<defs>' + innerSVG(defsNode) + '</defs>' : '';
Expand Down
71 changes: 34 additions & 37 deletions lib/draw/BpmnRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ import Ids from 'ids';

import { black } from './BpmnRenderUtil';

var rendererIds = new Ids();
var markerIds = new Ids();

var ELEMENT_LABEL_DISTANCE = 10,
INNER_OUTER_DIST = 3,
Expand Down Expand Up @@ -116,10 +116,6 @@ export default function BpmnRenderer(
defaultStrokeColor = config && config.defaultStrokeColor,
defaultLabelColor = config && config.defaultLabelColor;

var rendererId = rendererIds.next();

var markers = {};

function shapeStyle(attrs) {
return styles.computeStyle(attrs, {
strokeLinecap: 'round',
Expand All @@ -143,7 +139,8 @@ export default function BpmnRenderer(
var {
ref = { x: 0, y: 0 },
scale = 1,
element
element,
parentGfx = canvas._svg
} = options;

var marker = svgCreate('marker', {
Expand All @@ -158,36 +155,28 @@ export default function BpmnRenderer(

svgAppend(marker, element);

var defs = domQuery('defs', canvas._svg);
var defs = domQuery(':scope > defs', parentGfx);

if (!defs) {
defs = svgCreate('defs');

svgAppend(canvas._svg, defs);
svgAppend(parentGfx, defs);
}

svgAppend(defs, marker);

markers[id] = marker;
}

function colorEscape(str) {
function marker(parentGfx, type, fill, stroke) {

// only allow characters and numbers
return str.replace(/[^0-9a-zA-Z]+/g, '_');
}

function marker(type, fill, stroke) {
var id = type + '-' + colorEscape(fill) + '-' + colorEscape(stroke) + '-' + rendererId;
var id = markerIds.nextPrefixed('marker-');

if (!markers[id]) {
createMarker(id, type, fill, stroke);
}
createMarker(parentGfx, id, type, fill, stroke);

return 'url(#' + id + ')';
}

function createMarker(id, type, fill, stroke) {
function createMarker(parentGfx, id, type, fill, stroke) {

if (type === 'sequenceflow-end') {
var sequenceflowEnd = svgCreate('path', {
Expand All @@ -202,7 +191,8 @@ export default function BpmnRenderer(
addMarker(id, {
element: sequenceflowEnd,
ref: { x: 11, y: 10 },
scale: 0.5
scale: 0.5,
parentGfx
});
}

Expand All @@ -224,7 +214,8 @@ export default function BpmnRenderer(

addMarker(id, {
element: messageflowStart,
ref: { x: 6, y: 6 }
ref: { x: 6, y: 6 },
parentGfx
});
}

Expand All @@ -244,7 +235,8 @@ export default function BpmnRenderer(

addMarker(id, {
element: messageflowEnd,
ref: { x: 8.5, y: 5 }
ref: { x: 8.5, y: 5 },
parentGfx
});
}

Expand All @@ -265,7 +257,8 @@ export default function BpmnRenderer(
addMarker(id, {
element: associationStart,
ref: { x: 1, y: 10 },
scale: 0.5
scale: 0.5,
parentGfx
});
}

Expand All @@ -286,7 +279,8 @@ export default function BpmnRenderer(
addMarker(id, {
element: associationEnd,
ref: { x: 11, y: 10 },
scale: 0.5
scale: 0.5,
parentGfx
});
}

Expand All @@ -302,22 +296,25 @@ export default function BpmnRenderer(
addMarker(id, {
element: conditionalFlowMarker,
ref: { x: -1, y: 10 },
scale: 0.5
scale: 0.5,
parentGfx
});
}

if (type === 'conditional-default-flow-marker') {
var defaultFlowMarker = svgCreate('path', {
d: 'M 6 4 L 10 16',
...shapeStyle({
stroke: stroke
stroke: stroke,
fill: 'none'
})
});

addMarker(id, {
element: defaultFlowMarker,
ref: { x: 0, y: 10 },
scale: 0.5
scale: 0.5,
parentGfx
});
}
}
Expand Down Expand Up @@ -1105,11 +1102,11 @@ export default function BpmnRenderer(

if (semantic.get('associationDirection') === 'One' ||
semantic.get('associationDirection') === 'Both') {
attrs.markerEnd = marker('association-end', fill, stroke);
attrs.markerEnd = marker(parentGfx, 'association-end', fill, stroke);
}

if (semantic.get('associationDirection') === 'Both') {
attrs.markerStart = marker('association-start', fill, stroke);
attrs.markerStart = marker(parentGfx, 'association-start', fill, stroke);
}

attrs = pickAttrs(attrs, [
Expand Down Expand Up @@ -1403,7 +1400,7 @@ export default function BpmnRenderer(

return renderAssociation(parentGfx, element, {
...attrs,
markerEnd: marker('association-end', getFillColor(element, defaultFillColor, attrs.fill), getStrokeColor(element, defaultStrokeColor, attrs.stroke))
markerEnd: marker(parentGfx, 'association-end', getFillColor(element, defaultFillColor, attrs.fill), getStrokeColor(element, defaultStrokeColor, attrs.stroke))
});
},
'bpmn:DataObject': function(parentGfx, element, attrs = {}) {
Expand Down Expand Up @@ -1441,7 +1438,7 @@ export default function BpmnRenderer(

return renderAssociation(parentGfx, element, {
...attrs,
markerEnd: marker('association-end', getFillColor(element, defaultFillColor, attrs.fill), getStrokeColor(element, defaultStrokeColor, attrs.stroke))
markerEnd: marker(parentGfx, 'association-end', getFillColor(element, defaultFillColor, attrs.fill), getStrokeColor(element, defaultStrokeColor, attrs.stroke))
});
},
'bpmn:DataStoreReference': function(parentGfx, element, attrs = {}) {
Expand Down Expand Up @@ -1707,8 +1704,8 @@ export default function BpmnRenderer(
stroke = getStrokeColor(element, defaultStrokeColor, attrs.stroke);

var path = drawConnectionSegments(parentGfx, element.waypoints, {
markerEnd: marker('messageflow-end', fill, stroke),
markerStart: marker('messageflow-start', fill, stroke),
markerEnd: marker(parentGfx, 'messageflow-end', fill, stroke),
markerStart: marker(parentGfx, 'messageflow-start', fill, stroke),
stroke,
strokeDasharray: '10, 11',
strokeWidth: 1.5
Expand Down Expand Up @@ -1964,7 +1961,7 @@ export default function BpmnRenderer(
stroke = getStrokeColor(element, defaultStrokeColor, attrs.stroke);

var connection = drawConnectionSegments(parentGfx, element.waypoints, {
markerEnd: marker('sequenceflow-end', fill, stroke),
markerEnd: marker(parentGfx, 'sequenceflow-end', fill, stroke),
stroke
});

Expand All @@ -1978,15 +1975,15 @@ export default function BpmnRenderer(
// conditional flow marker
if (semantic.get('conditionExpression') && is(sourceSemantic, 'bpmn:Activity')) {
svgAttr(connection, {
markerStart: marker('conditional-flow-marker', fill, stroke)
markerStart: marker(parentGfx, 'conditional-flow-marker', fill, stroke)
});
}

// default marker
if (sourceSemantic.get('default') && (is(sourceSemantic, 'bpmn:Gateway') || is(sourceSemantic, 'bpmn:Activity')) &&
sourceSemantic.get('default') === semantic) {
svgAttr(connection, {
markerStart: marker('conditional-default-flow-marker', fill, stroke)
markerStart: marker(parentGfx, 'conditional-default-flow-marker', fill, stroke)
});
}
}
Expand Down
58 changes: 38 additions & 20 deletions test/spec/draw/BpmnRendererSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ describe('draw - bpmn renderer', function() {
var svg = canvas._svg;
var markers = svg.querySelectorAll('marker');

expect(markers[0].id).to.match(/^sequenceflow-end-white-hsl_225_10_15_-[A-Za-z0-9]+$/);
expect(markers[0].id).to.match(/^marker-[A-Za-z0-9]+$/);
})();
});
});
Expand All @@ -375,17 +375,26 @@ describe('draw - bpmn renderer', function() {
expect(err).not.to.exist;

inject(function(canvas) {
var svg = canvas._svg,
markers = svg.querySelectorAll('marker');

expect(markers).to.have.length(7);
expect(markers[0].id).to.match(/^sequenceflow-end-rgb_255_224_178_-rgb_251_140_0_-[A-Za-z0-9]{25}$/);
expect(markers[1].id).to.match(/^sequenceflow-end-yellow-blue-[A-Za-z0-9]{25}$/);
expect(markers[2].id).to.match(/^sequenceflow-end-white-_FB8C00-[A-Za-z0-9]{25}$/);
expect(markers[3].id).to.match(/^sequenceflow-end-white-rgba_255_0_0_0_9_-[A-Za-z0-9]{25}$/);
expect(markers[4].id).to.match(/^association-end-_FFE0B2-_FB8C00-[A-Za-z0-9]{25}$/);
expect(markers[5].id).to.match(/^messageflow-end-_FFE0B2-_FB8C00-[A-Za-z0-9]{25}$/);
expect(markers[6].id).to.match(/^messageflow-start-_FFE0B2-_FB8C00-[A-Za-z0-9]{25}$/);

[
[ 'SequenceFlow_1jrsqqc' , 'blue' , 'blue' ],
[ 'SequenceFlow_0h9s0mp' , 'rgba(255, 0, 0, 0.9)' ],
[ 'SequenceFlow_0pqo7zt' , 'rgb(251, 140, 0)' , 'rgb(251, 140, 0)' ],
[ 'SequenceFlow_1qt82pt' , 'blue' , 'blue' ],
[ 'SequenceFlow_17ohrlh' , 'rgb(251, 140, 0)' , 'rgb(251, 140, 0)' ],
[ 'MessageFlow_11bysyp' , 'rgb(251, 140, 0)' , 'rgb(255, 224, 178)' ],
[ 'MessageFlow_1qyovto' , 'rgb(251, 140, 0)' , 'rgb(255, 224, 178)' ],
[ 'DataInputAssociation_1ncouqr' , 'rgb(251, 140, 0)' , 'none' ],
[ 'DataOutputAssociation_1i89wkc' , 'rgb(251, 140, 0)' , 'none' ]
].forEach(([ id, stroke, fill ]) => {
var svg = canvas._svg,
markerPath = svg.querySelector(`[data-element-id="${id}"] marker path`);

expect(markerPath).to.exist;

stroke && expect(markerPath.style.stroke).to.eql(stroke);
fill && expect(markerPath.style.fill).to.eql(fill);
});
})();
});
});
Expand All @@ -401,14 +410,23 @@ describe('draw - bpmn renderer', function() {
expect(err).not.to.exist;

inject(function(canvas) {
var svg = canvas._svg,
markers = svg.querySelectorAll('marker');

expect(markers).to.have.length(4);
expect(markers[0].id).to.match(/^association-end-rgb_23_100_344_-rgb_23_100_344_-[A-Za-z0-9]{25}$/);
expect(markers[1].id).to.match(/^association-end-_E1BEE7-_8E24AA-[A-Za-z0-9]{25}$/);
expect(markers[2].id).to.match(/^messageflow-end-rgb_23_100_344_-rgb_23_100_344_-[A-Za-z0-9]{25}$/);
expect(markers[3].id).to.match(/^messageflow-start-rgb_23_100_344_-rgb_23_100_344_-[A-Za-z0-9]{25}$/);

[
[ 'MessageFlow_1facuin', 'rgb(23, 100, 255)', 'rgb(23, 100, 255)' ],
[ 'MessageFlow_1vmbq3n', 'rgb(23, 100, 255)', 'rgb(23, 100, 255)' ],
[ 'DataInputAssociation', 'rgb(23, 100, 255)', 'none' ],
[ 'DataOutputAssociation_0ixhole', 'rgb(142, 36, 170)', 'none' ],
].forEach(([ id, stroke, fill ]) => {
var svg = canvas._svg,
markerPath = svg.querySelector(`[data-element-id="${id}"] marker path`);

console.log(id, markerPath);
expect(markerPath).to.exist;

stroke && expect(markerPath.style.stroke).to.eql(stroke);
fill && expect(markerPath.style.fill).to.eql(fill);

});
})();
});
});
Expand Down

0 comments on commit d616a34

Please sign in to comment.