feat(bpmnrenderer): gateway renndering added

closes #17
This commit is contained in:
jdotzki 2014-04-24 12:25:04 +02:00
parent bcf6e1900e
commit 21b1ac0ab0
3 changed files with 335 additions and 16 deletions

View File

@ -494,12 +494,148 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) {
var rect = drawRect(p, data.width, data.height, 0); var rect = drawRect(p, data.width, data.height, 0);
return rect; return rect;
}, },
'bpmn:InclusiveGateway': function(p, data) {
var diamond = drawDiamond(p, data.width, data.height);
'bpmn:InclusiveGateway': as('bpmn:Gateway'), var circle = drawCircle(p, data.width, data.height, data.height * 0.24);
'bpmn:ExclusiveGateway': as('bpmn:Gateway'), circle.attr({
'bpmn:ComplexGateway': as('bpmn:Gateway'), 'stroke-width': 2.5,
'bpmn:ParallelGateway': as('bpmn:Gateway'), 'fill': 'None'
'bpmn:EventBasedGateway': as('bpmn:Gateway'), });
return diamond;
},
'bpmn:ExclusiveGateway': function(p, data) {
var diamond = drawDiamond(p, data.width, data.height);
var pathData = pathMap.getScaledPath('GATEWAY_EXCLUSIVE', {
xScaleFactor: 0.45,
yScaleFactor: 0.45,
containerWidth: data.width,
containerHeight: data.height,
position: {
mx: 0.3,
my: 0.28
}
});
var exclusivePath = drawPath(p, pathData);
exclusivePath.attr({
'stroke-width': 1,
'fill': 'Black'
});
return diamond;
},
'bpmn:ComplexGateway': function(p, data) {
var diamond = drawDiamond(p, data.width, data.height);
var pathData = pathMap.getScaledPath('GATEWAY_COMPLEX', {
xScaleFactor: 0.5,
yScaleFactor:0.5,
containerWidth: data.width,
containerHeight: data.height,
position: {
mx: 0.46,
my: 0.26
}
});
var complexPath = drawPath(p, pathData);
complexPath.attr({
'stroke-width': 1,
'fill': 'Black'
});
return diamond;
},
'bpmn:ParallelGateway': function(p, data) {
var diamond = drawDiamond(p, data.width, data.height);
var pathData = pathMap.getScaledPath('GATEWAY_PARALLEL', {
xScaleFactor: 0.6,
yScaleFactor:0.6,
containerWidth: data.width,
containerHeight: data.height,
position: {
mx: 0.46,
my: 0.2
}
});
var parallelPath = drawPath(p, pathData);
parallelPath.attr({
'stroke-width': 1,
'fill': 'Black'
});
return diamond;
},
'bpmn:EventBasedGateway': function(p, data) {
var diamond = drawDiamond(p, data.width, data.height);
var outerCircle = drawCircle(p, data.width, data.height, data.height * 0.21);
outerCircle.attr({
'stroke-width': 1,
'fill': 'None'
});
var type = bpmnRegistry.getSemantic(data.id).eventGatewayType;
function drawEvent() {
var pathData = pathMap.getScaledPath('GATEWAY_EVENT_BASED', {
xScaleFactor: 0.20,
yScaleFactor: 0.20,
containerWidth: data.width,
containerHeight: data.height,
position: {
mx: 0.34,
my: 0.43
}
});
var eventPath = drawPath(p, pathData);
eventPath.attr({
'stroke-width': 2,
'fill': 'None'
});
}
if(type === 'Parallel') {
var pathData = pathMap.getScaledPath('GATEWAY_PARALLEL', {
xScaleFactor: 0.4,
yScaleFactor:0.4,
containerWidth: data.width,
containerHeight: data.height,
position: {
mx: 0.46,
my: 0.29
}
});
var parallelPath = drawPath(p, pathData);
parallelPath.attr({
'stroke-width': 1,
'fill': 'None'
});
} else if(type === 'Exclusive') {
drawEvent();
} else {
var innerCircle = drawCircle(p, data.width, data.height, data.height * 0.24);
innerCircle.attr({
'stroke-width': 1,
'fill': 'None'
});
drawEvent();
}
return diamond;
},
'bpmn:Gateway': function(p, data) { 'bpmn:Gateway': function(p, data) {
var diamond = drawDiamond(p, data.width, data.height); var diamond = drawDiamond(p, data.width, data.height);

View File

@ -8,6 +8,34 @@ function PathMap(Snap) {
/** /**
* Contains a map of path elements * Contains a map of path elements
*
* <h1>Path definition</h1>
* A parameterized path is defined like this:
* <pre>
* 'GATEWAY_PARALLEL': {
* d: 'm {mx},{my} {e.x0},0 0,{e.x1} {e.x1},0 0,{e.y0} -{e.x1},0 0,{e.y1} ' +
'-{e.x0},0 0,-{e.y1} -{e.x1},0 0,-{e.y0} {e.x1},0 z',
* height: 17.5,
* width: 17.5,
* heightElements: [2.5, 7.5],
* widthElements: [2.5, 7.5]
* }
* </pre>
* <p>It's important to specify a correct <b>height and width</b> for the path as the scaling
* is based on the ratio between the specified height and width in this object and the
* height and width that is set as scale target (Note x,y coordinates will be scaled with
* individual ratios).</p>
* <p>The '<b>heightElements</b>' and '<b>widthElements</b>' array must contain the values that will be scaled.
* The scaling is based on the computed ratios.
* Coordinates on the y axis should be in the <b>heightElement</b>'s array, they will be scaled using
* the computed ratio coefficient.
* In the parameterized path the scaled values can be accessed through the 'e' object in {} brackets.
* <ul>
* <li>The values for the y axis can be accessed in the path string using {e.y0}, {e.y1}, ....</li>
* <li>The values for the x axis can be accessed in the path string using {e.x0}, {e.x1}, ....</li>
* </ul>
* The numbers x0, x1 respectively y0, y1, ... map to the corresponding array index.
* </p>
*/ */
this.pathMap = { this.pathMap = {
'shape': { 'shape': {
@ -173,6 +201,46 @@ function PathMap(Snap) {
width: 17, width: 17,
heightElements: [], heightElements: [],
widthElements: [] widthElements: []
},
'GATEWAY_EXCLUSIVE': {
//m 0,0 6.5,8.5 -6.5,8.5 3,0 5,-6.5312 5,6.5312 3,0 -6.5,-8.5 6.5,-8.5 -3,0 -5,6.5313 -5,-6.5313 -3,0 z
d:'m {mx},{my} {e.x0},{e.y0} {e.x1},{e.y0} {e.x2},0 {e.x4},{e.y2} ' +
'{e.x4},{e.y1} {e.x2},0 {e.x1},{e.y3} {e.x0},{e.y3} ' +
'{e.x3},0 {e.x5},{e.y1} {e.x5},{e.y2} {e.x3},0 z',
height: 17.5,
width: 17.5,
heightElements: [8.5, 6.5312, -6.5312, -8.5],
widthElements: [6.5, -6.5, 3, -3, 5, -5]
},
'GATEWAY_PARALLEL': {
d:'m {mx},{my} {e.x0},0 0,{e.x1} {e.x1},0 0,{e.y0} -{e.x1},0 0,{e.y1} ' +
'-{e.x0},0 0,-{e.y1} -{e.x1},0 0,-{e.y0} {e.x1},0 z',
height: 17.125,
width: 16.125,
heightElements: [2.5, 7.5],
widthElements: [2.5, 7.5]
},
'GATEWAY_EVENT_BASED': {
//d:'m {mx},{my} 9.42149,-6.28099 9.42149,6.28099 -3.1405,12.56199 -12.56198,0 z',
d:'m {mx},{my} {e.x0},{e.y0} {e.x0},{e.y1} {e.x1},{e.y2} {e.x2},0 z',
height: 11,
width: 11,
heightElements: [-6, 6, 12, -12],
widthElements: [9, -3, -12]
},
'GATEWAY_COMPLEX': {
//d:'m 7.0625,0.0625 0,4.8750001 -3.4375,-3.4375 -2.125,2.125 3.4375,3.4375 -4.875,0
// 0,2.9999999 4.875,0 L 1.5,13.5 l 2.125,2.125 3.4375,-3.4375 0,4.875 3,0 0,-4.875
// 3.4375,3.4375 2.125,-2.125 -3.4375,-3.4375 4.875,0 0,-2.9999999 -4.875,0 3.4375,-3.4375
// -2.125,-2.125 -3.4375,3.4375 0,-4.8750001 z',
d:'m {mx},{my} 0,{e.y0} -{e.x0},-{e.y1} -{e.x1},{e.y2} {e.x0},{e.y1} -{e.x2},0 0,{e.y3} ' +
'{e.x2},0 -{e.x0},{e.y1} l {e.x1},{e.y2} {e.x0},-{e.y1} 0,{e.y0} {e.x3},0 0,-{e.y0} {e.x0},{e.y1} ' +
'{e.x1},-{e.y2} -{e.x0},-{e.y1} {e.x2},0 0,-{e.y3} -{e.x2},0 {e.x0},-{e.y1} -{e.x1},-{e.y2} ' +
'-{e.x0},{e.y1} 0,-{e.y0} -{e.x3},0 z',
height: 17.125,
width: 17.125,
heightElements: [4.875, 3.4375, 2.125, 3],
widthElements: [3.4375, 2.125, 4.875, 3]
} }
}; };
@ -182,32 +250,85 @@ function PathMap(Snap) {
/** /**
* Scales the path to the given height and width. * Scales the path to the given height and width.
* <h1>Use case</h1>
* <p>Use case is to scale the content of elements (event, gateways) based
* on the element bounding box's size.
* </p>
* <h1>Why not transform</h1>
* <p>Scaling a path with transform() will also scale the stroke and IE does not support
* the option 'non-scaling-stroke' to prevent this.
* Also there are use cases where only some parts of a path should be
* scaled.</p>
*
* @param {String} pathId The ID of the path.
* @param {Object} param <p>
* Example param object scales the path to 60% size of the container (data.width, data.height).
* <pre>
* {
* xScaleFactor: 0.6,
* yScaleFactor:0.6,
* containerWidth: data.width,
* containerHeight: data.height,
* position: {
* mx: 0.46,
* my: 0.2,
* }
* }
* </pre>
* <ul>
* <li>targetpathwidth = xScaleFactor * containerWidth</li>
* <li>targetpathheight = yScaleFactor * containerHeight</li>
* <li>Position is used to set the starting coordinate of the path. M is computed:
* <ul>
* <li>position.x * containerWidth</li>
* <li>position.y * containerHeight</li>
* </ul>
* Center of the container <pre> position: {
* mx: 0.5,
* my: 0.5,
* }</pre>
* Upper left corner of the container
* <pre> position: {
* mx: 0.0,
* my: 0.0,
* }</pre>
* </li>
* </ul>
* </p>
*
*/ */
this.getScaledPath = function getScaledPath(pathId, height, width) { this.getScaledPath = function getScaledPath(pathId, param) {
var rawPath = this.getRawPath(pathId); var rawPath = this.pathMap[pathId];
var heightRatio = rawPath.height / height;
var widthRatio = rawPath.width / width; // positioning
var heightElements = []; // compute the start point of the path
var widthElements = []; var mx = param.containerWidth * param.position.mx;
var my = param.containerHeight * param.position.my;
// path
var heightRatio = (param.containerHeight * param.yScaleFactor) / rawPath.height;
var widthRatio = (param.containerWidth * param.xScaleFactor) / rawPath.width;
var coordinates = {}; //map for the scaled coordinates
//Apply height ratio //Apply height ratio
for(var heightIndex = 0; heightIndex < rawPath.heightElements.length; heightIndex++) { for(var heightIndex = 0; heightIndex < rawPath.heightElements.length; heightIndex++) {
heightElements[heightIndex] = rawPath.heightElements[heightIndex] * heightRatio; coordinates['y' + heightIndex] = rawPath.heightElements[heightIndex] * heightRatio;
} }
//Apply width ratio //Apply width ratio
for(var widthIndex = 0; widthIndex < rawPath.widthElements.length; widthIndex++) { for(var widthIndex = 0; widthIndex < rawPath.widthElements.length; widthIndex++) {
widthElements[widthIndex] = rawPath.widthElements[widthIndex] * widthRatio; coordinates['x' + widthIndex] = rawPath.widthElements[widthIndex] * widthRatio;
} }
//Apply value to raw path //Apply value to raw path
var path = Snap.format( var path = Snap.format(
rawPath.d, { rawPath.d, {
heightElements: heightElements, mx: mx,
widthElements: widthElements my: my,
e: coordinates
} }
); );
return path; return path;
}; };
} }

62
test/fixtures/bpmn/render/gateways.bpmn vendored Normal file
View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd"
id="gateway-testcase"
targetNamespace="http://bpmn.io/schema/bpmn">
<bpmn:process id="Process_1" isExecutable="false">
<bpmn:inclusiveGateway id="InclusiveGateway_1"/>
<bpmn:exclusiveGateway id="ExclusiveGateway_1"/>
<bpmn:parallelGateway id="ParallelGateway_1"/>
<bpmn:eventBasedGateway id="EventBasedGateway_1"/>
<bpmn:complexGateway id="ComplexGateway_1"/>
<bpmn:eventBasedGateway id="EventBasedGateway_2" eventGatewayType="Parallel"/>
<bpmn:eventBasedGateway id="EventBasedGateway_3" eventGatewayType="Exclusive"/>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="_BPMNShape_InclusiveGateway_2" bpmnElement="InclusiveGateway_1">
<dc:Bounds height="50.0" width="50.0" x="114.0" y="99.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_ExclusiveGateway_2" bpmnElement="ExclusiveGateway_1" isMarkerVisible="true">
<dc:Bounds height="50.0" width="50.0" x="229.0" y="99.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="254.0" y="154.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_ParallelGateway_2" bpmnElement="ParallelGateway_1">
<dc:Bounds height="50.0" width="50.0" x="336.0" y="99.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="361.0" y="154.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_EventBasedGateway_2" bpmnElement="EventBasedGateway_1">
<dc:Bounds height="50.0" width="50.0" x="456.0" y="99.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="481.0" y="154.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_ComplexGateway_2" bpmnElement="ComplexGateway_1">
<dc:Bounds height="50.0" width="50.0" x="576.0" y="99.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="601.0" y="154.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_EventBasedGateway_3" bpmnElement="EventBasedGateway_2">
<dc:Bounds height="50.0" width="50.0" x="690.0" y="99.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="481.0" y="154.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_EventBasedGateway_4" bpmnElement="EventBasedGateway_3">
<dc:Bounds height="50.0" width="50.0" x="820.0" y="99.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="0.0" width="0.0" x="481.0" y="154.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>