From 645d0e8ea4c536301103ee87a44a1a4ee3a1a7af Mon Sep 17 00:00:00 2001 From: Nico Rehwaldt Date: Tue, 27 May 2014 17:51:16 +0200 Subject: [PATCH] fix(BpmnRenderer): correctly draw boundaryEvent#cancelActivity Closes #71 --- lib/draw/BpmnRenderer.js | 764 +++++++++++++++++++-------------------- 1 file changed, 369 insertions(+), 395 deletions(-) diff --git a/lib/draw/BpmnRenderer.js b/lib/draw/BpmnRenderer.js index 8c7d0104..3c22dabf 100644 --- a/lib/draw/BpmnRenderer.js +++ b/lib/draw/BpmnRenderer.js @@ -1,3 +1,5 @@ +'use strict'; + var bpmnModule = require('../di').defaultModule; var _ = require('lodash'); @@ -14,6 +16,7 @@ var LabelUtil = require('diagram-js/lib/util/LabelUtil'); var flattenPoints = DefaultRenderer.flattenPoints; + function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { DefaultRenderer.apply(this, [ events, styles ]); @@ -47,8 +50,8 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { paper .path('M 0 0 L 10 5 L 0 10 Z') .attr({ - 'fill': 'black', - 'stroke': 'none' + fill: 'black', + stroke: 'none' }) .marker(0, 0, 10, 10, 10, 5) .attr({ @@ -65,8 +68,8 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { .attr({ fill: 'white', stroke: 'black', - 'stroke-width': 1, - 'stroke-dasharray': '1,0' + strokeWidth: 1, + strokeDasharray: '1,0' }) .marker(0, 0, 10, 10, 4, 4) .attr({ @@ -83,9 +86,9 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { .attr({ stroke: 'black', fill: 'white', - 'stroke-width': 1, - 'stroke-linecap': 'round', - 'stroke-dasharray': '1,0' + strokeWidth: 1, + strokeLinecap: 'round', + strokeDasharray: '1,0' }) .marker(0, 0, 10, 10, 11, 5) .attr({ @@ -104,16 +107,16 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { .attr({ stroke: 'black', fill: 'none', - 'stroke-width': 1.5, - 'stroke-linecap': 'round', - 'stroke-dasharray': '1,0' + strokeWidth: 1.5, + strokeLinecap: 'round', + strokeDasharray: '1,0' })); addMarker('data-association-end', paper .path('M 0 0 L 10 5 L 0 10') .attr({ - 'fill': 'white', - 'stroke': 'Black' + fill: 'white', + stroke: 'Black' }) .marker(0, 0, 10, 10, 10, 5) .attr({ @@ -122,16 +125,16 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { markerHeight: 9.6, orient: 'auto', overflow: 'visible', - 'stroke-width': 1, - 'stroke-dasharray': '1,0' + strokeWidth: 1, + strokeDasharray: '1,0' })); addMarker('conditional-flow-marker', paper .path('M 0,0 7.089123,3.1832974 0.00383366,6.1129516 -7.0814464,3.1832966 z') .attr({ - 'fill': 'White', - 'stroke': 'Black' + fill: 'White', + stroke: 'Black' }) .marker(0, 0, 15, 15, 0, 0) .attr({ @@ -140,18 +143,18 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { markerHeight: 12, orient: 'auto', overflow: 'visible', - 'stroke-width': 1, - 'stroke-dasharray': '1,0', - 'refX': -8, - 'refY': 3.15 + strokeWidth: 1, + strokeDasharray: '1,0', + refX: -8, + refY: 3.15 })); addMarker('conditional-default-flow-marker', paper .path('M 3,0 10,11') .attr({ - 'fill': 'Black', - 'stroke': 'Black' + fill: 'Black', + stroke: 'Black' }) .marker(0, 0, 15, 15, 0, 0) .attr({ @@ -160,71 +163,97 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { markerHeight: 13, orient: 'auto', overflow: 'visible', - 'stroke-width': 1, - 'stroke-dasharray': '1,0', - 'refX': -4, - 'refY': 5.5 + strokeWidth: 1, + strokeDasharray: '1,0', + refX: -4, + refY: 5.5 })); } - function drawCircle(p, width, height, offset) { + function computeStyle(custom, traits, defaultStyles) { + if (!_.isArray(traits)) { + defaultStyles = traits; + traits = []; + } + + return styles.style(traits || [], _.extend(defaultStyles, custom || {})); + } + + function drawCircle(p, width, height, offset, attrs) { + + if (_.isObject(offset)) { + attrs = offset; + offset = 0; + } offset = offset || 0; + attrs = computeStyle(attrs, { + stroke: 'Black', + strokeWidth: 1, + fill: 'White' + }); + var cx = width / 2, cy = height / 2; - return p.circle(cx, cy, Math.round((width + height) / 4 - offset)).attr({ - 'stroke': 'Black', - 'stroke-width': 1, - 'fill': 'White' - }); + return p.circle(cx, cy, Math.round((width + height) / 4 - offset)).attr(attrs); } - function drawRect(p, width, height, r, offset) { + function drawRect(p, width, height, r, offset, attrs) { + + if (_.isObject(offset)) { + attrs = offset; + offset = 0; + } + offset = offset || 0; - return p.rect(offset, offset, width - offset * 2, height - offset * 2, r).attr({ - 'stroke': 'Black', - 'stroke-width': 2, - 'fill': 'White' + attrs = computeStyle(attrs, { + stroke: 'Black', + strokeWidth: 2, + fill: 'White' }); + + return p.rect(offset, offset, width - offset * 2, height - offset * 2, r).attr(attrs); } - function drawDiamond(p, width, height) { + function drawDiamond(p, width, height, attrs) { var x_2 = width / 2; var y_2 = height / 2; var points = [x_2, 0, width, y_2, x_2, height, 0, y_2 ]; - return p.polygon(points).attr({ - 'stroke': 'Black', - 'stroke-width': 2, - 'fill': 'White' + attrs = computeStyle(attrs, { + stroke: 'Black', + strokeWidth: 2, + fill: 'White' }); + + return p.polygon(points).attr(attrs); } - function drawLine(p, waypoints) { + function drawLine(p, waypoints, attrs) { var points = flattenPoints(waypoints); - return p.polyline(points).attr(styles.style([ 'no-fill' ], { - 'stroke-width': 2, - 'stroke': 'Black' - })); + attrs = computeStyle(attrs, [ 'no-fill' ], { + stroke: 'Black', + strokeWidth: 2, + fill: 'White' + }); + + return p.polyline(points).attr(attrs); } - function drawPath(p, d, fill) { + function drawPath(p, d, attrs) { - var fillColor = fill ? 'Black' : 'None'; + attrs = computeStyle(attrs, [ 'no-fill' ], { + strokeWidth: 1, + stroke: 'Black' + }); - var path = p.path(d).attr(styles.style([ 'no-fill' ],{ - 'stroke-width': 1, - 'stroke': 'Black', - 'fill': fillColor - })); - - return path; + return p.path(d).attr(attrs); } function as(type) { @@ -318,29 +347,33 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { var top = -1 * data.height; textBox.transform( - 'rotate(270) ' + - 'translate(' + top + ',' + 0 + ')' + 'rotate(270) ' + + 'translate(' + top + ',' + 0 + ')' ); } function createPathFromWaypoints(waypoints) { - var linePathData = 'm ' + waypoints[0].x + ',' + waypoints[0].y; + var pathData = 'm ' + waypoints[0].x + ',' + waypoints[0].y; for (var i = 1; i < waypoints.length; i++) { - linePathData += 'L' + waypoints[i].x + ',' + waypoints[i].y + ' '; + pathData += 'L' + waypoints[i].x + ',' + waypoints[i].y + ' '; } - return linePathData; + return pathData; } var handlers = { - 'bpmn:Event': function(p, data) { - return drawCircle(p, data.width, data.height); + 'bpmn:Event': function(p, data, attrs) { + return drawCircle(p, data.width, data.height, attrs); }, 'bpmn:StartEvent': function(p, data) { - var circle = renderer('bpmn:Event')(p, data); + var attrs = {}; + var semantic = getSemantic(data); - if(!bpmnRegistry.getSemantic(data.id).isInterrupting) { - circle.attr('stroke-dasharray', '5,2'); + if (!semantic.isInterrupting) { + attrs = { strokeDasharray: '5,2' }; } + + var circle = renderer('bpmn:Event')(p, data, attrs); + renderEventContent(data, p); return circle; @@ -360,20 +393,18 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { var fill = isThrowing ? 'Black' : 'None'; var stroke = isThrowing ? 'White' : 'Black'; - var messagePath = drawPath(p, pathData); - messagePath.attr({ - 'stroke-width': 1, - 'fill': fill, - 'stroke': stroke + var messagePath = drawPath(p, pathData, { + strokeWidth: 1, + fill: fill, + stroke: stroke }); return messagePath; }, 'bpmn:TimerEventDefinition': function(p, data) { - var circle = drawCircle(p, data.width, data.height, 0.2 * data.height); - circle.attr({ - 'stroke-width': 2 + var circle = drawCircle(p, data.width, data.height, 0.2 * data.height, { + strokeWidth: 2 }); var pathData = pathMap.getScaledPath('EVENT_TIMER_WH', { @@ -387,9 +418,8 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { } }); - var timerPathWh = drawPath(p, pathData); - timerPathWh.attr({ - 'stroke-width': 2 + var path = drawPath(p, pathData, { + strokeWidth: 2 }); return circle; @@ -408,13 +438,10 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { var fill = isThrowing ? 'Black' : 'None'; - var escalationPath = drawPath(p, pathData); - escalationPath.attr({ - 'stroke-width': 1, - 'fill': fill + return drawPath(p, pathData, { + strokeWidth: 1, + fill: fill }); - - return escalationPath; }, 'bpmn:ConditionalEventDefinition': function(p, event) { var pathData = pathMap.getScaledPath('EVENT_CONDITIONAL', { @@ -428,12 +455,9 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { } }); - var conditionalPath = drawPath(p, pathData); - conditionalPath.attr({ - 'stroke-width': 1 + return drawPath(p, pathData, { + strokeWidth: 1 }); - - return conditionalPath; }, 'bpmn:LinkEventDefinition': function(p, event) { var pathData = pathMap.getScaledPath('EVENT_LINK', { @@ -447,12 +471,9 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { } }); - var linkPath = drawPath(p, pathData); - linkPath.attr({ - 'stroke-width': 1 + return drawPath(p, pathData, { + strokeWidth: 1 }); - - return linkPath; }, 'bpmn:ErrorEventDefinition': function(p, event, isThrowing) { var pathData = pathMap.getScaledPath('EVENT_ERROR', { @@ -468,13 +489,10 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { var fill = isThrowing ? 'Black' : 'None'; - var errorPath = drawPath(p, pathData); - errorPath.attr({ - 'stroke-width': 1, - 'fill': fill + return drawPath(p, pathData, { + strokeWidth: 1, + fill: fill }); - - return errorPath; }, 'bpmn:CancelEventDefinition': function(p, event, isThrowing) { var pathData = pathMap.getScaledPath('EVENT_CANCEL_45', { @@ -490,15 +508,10 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { var fill = isThrowing ? 'Black' : 'None'; - var cancelPath = drawPath(p, pathData); - cancelPath.attr({ - 'stroke-width': 1, - 'fill': fill - }); - - cancelPath.transform('rotate(45)'); - - return cancelPath; + return drawPath(p, pathData, { + strokeWidth: 1, + fill: fill + }).transform('rotate(45)'); }, 'bpmn:CompensateEventDefinition': function(p, event, isThrowing) { var pathData = pathMap.getScaledPath('EVENT_COMPENSATION', { @@ -514,13 +527,10 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { var fill = isThrowing ? 'Black' : 'None'; - var compensationPath = drawPath(p, pathData); - compensationPath.attr({ - 'stroke-width': 1, - 'fill': fill + return drawPath(p, pathData, { + strokeWidth: 1, + fill: fill }); - - return compensationPath; }, 'bpmn:SignalEventDefinition': function(p, event, isThrowing) { var pathData = pathMap.getScaledPath('EVENT_SIGNAL', { @@ -536,13 +546,10 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { var fill = isThrowing ? 'Black' : 'None'; - var signalPath = drawPath(p, pathData); - signalPath.attr({ - 'stroke-width': 1, - 'fill': fill + return drawPath(p, pathData, { + strokeWidth: 1, + fill: fill }); - - return signalPath; }, 'bpmn:MultipleEventDefinition': function(p, event, isThrowing) { var pathData = pathMap.getScaledPath('EVENT_MULTIPLE', { @@ -558,13 +565,10 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { var fill = isThrowing ? 'Black' : 'None'; - var multiplePath = drawPath(p, pathData); - multiplePath.attr({ - 'stroke-width': 1, - 'fill': fill + return drawPath(p, pathData, { + strokeWidth: 1, + fill: fill }); - - return multiplePath; }, 'bpmn:ParallelMultipleEventDefinition': function(p, event) { var pathData = pathMap.getScaledPath('EVENT_PARALLEL_MULTIPLE', { @@ -578,19 +582,13 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { } }); - var multiplePath = drawPath(p, pathData); - - multiplePath.attr({ - 'stroke-width': 1 + return drawPath(p, pathData, { + strokeWidth: 1 }); - - return multiplePath; }, 'bpmn:EndEvent': function(p, data) { - var circle = renderer('bpmn:Event')(p, data); - - circle.attr({ - 'stroke-width': 4 + var circle = renderer('bpmn:Event')(p, data, { + strokeWidth: 4 }); renderEventContent(data, p, true); @@ -598,11 +596,9 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { return circle; }, 'bpmn:TerminateEventDefinition': function(p, data) { - var circle = drawCircle(p, data.width, data.height, 7); - - circle.attr({ - 'stroke-width': 4, - 'fill': 'Black' + var circle = drawCircle(p, data.width, data.height, 8, { + strokeWidth: 4, + fill: 'Black' }); return circle; @@ -611,22 +607,6 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { var outer = renderer('bpmn:Event')(p, data); var inner = drawCircle(p, data.width, data.height, INNER_OUTER_DIST); - outer.attr('stroke-width', 1); - inner.attr('stroke-width', 1); - - renderEventContent(data, p); - - return outer; - }, - 'bpmn:IntermediateNonInterruptingEvent': function(p, data) { - var outer = renderer('bpmn:Event')(p, data); - var inner = drawCircle(p, data.width, data.height, INNER_OUTER_DIST); - - outer.attr('stroke-width', 1); - outer.attr('stroke-dasharray', '4'); - inner.attr('stroke-width', 1); - inner.attr('stroke-dasharray', '5'); - renderEventContent(data, p); return outer; @@ -634,8 +614,8 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { 'bpmn:IntermediateCatchEvent': as('bpmn:IntermediateEvent'), 'bpmn:IntermediateThrowEvent': as('bpmn:IntermediateEvent'), - 'bpmn:Activity': function(p, data) { - return drawRect(p, data.width, data.height, TASK_BORDER_RADIUS); + 'bpmn:Activity': function(p, data, attrs) { + return drawRect(p, data.width, data.height, TASK_BORDER_RADIUS, attrs); }, 'bpmn:Task': function(p, data) { @@ -654,10 +634,9 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { } }); - var servicePathBG = drawPath(p, pathDataBG); - servicePathBG.attr({ - 'stroke-width': 1, - 'fill': 'None' + var servicePathBG = drawPath(p, pathDataBG, { + strokeWidth: 1, + fill: 'None' }); var fillPathData = pathMap.getScaledPath('TASK_TYPE_SERVICE_FILL', { @@ -667,11 +646,10 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { } }); - var serviceFillPath = drawPath(p, fillPathData); - serviceFillPath.attr({ - 'stroke-width': 0, - 'stroke': 'none', - 'fill': 'White' + var serviceFillPath = drawPath(p, fillPathData, { + strokeWidth: 0, + stroke: 'none', + fill: 'White' }); var pathData = pathMap.getScaledPath('TASK_TYPE_SERVICE', { @@ -681,14 +659,11 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { } }); - var servicePath = drawPath(p, pathData); - servicePath.attr({ - 'stroke-width': 1, - 'fill': 'White' + var servicePath = drawPath(p, pathData, { + strokeWidth: 1, + fill: 'White' }); - - return task; }, 'bpmn:UserTask': function(p, data) { @@ -704,10 +679,9 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { } }); - var userPath = drawPath(p, pathData); - userPath.attr({ - 'stroke-width': 0.5, - 'fill': 'None' + var userPath = drawPath(p, pathData, { + strokeWidth: 0.5, + fill: 'None' }); var pathData2 = pathMap.getScaledPath('TASK_TYPE_USER_2', { @@ -717,10 +691,9 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { } }); - var userPath2 = drawPath(p, pathData2); - userPath2.attr({ - 'stroke-width': 0.5, - 'fill': 'None' + var userPath2 = drawPath(p, pathData2, { + strokeWidth: 0.5, + fill: 'None' }); var pathData3 = pathMap.getScaledPath('TASK_TYPE_USER_3', { @@ -730,10 +703,9 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { } }); - var userPath3 = drawPath(p, pathData3); - userPath3.attr({ - 'stroke-width': 0.5, - 'fill': 'Black' + var userPath3 = drawPath(p, pathData3, { + strokeWidth: 0.5, + fill: 'Black' }); return task; @@ -748,11 +720,10 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { } }); - var userPath = drawPath(p, pathData); - userPath.attr({ - 'stroke-width': 0.25, - 'fill': 'None', - 'stroke': 'Black' + var userPath = drawPath(p, pathData, { + strokeWidth: 0.25, + fill: 'None', + stroke: 'Black' }); return task; @@ -771,20 +742,21 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { } }); - var sendPath = drawPath(p, pathData); - sendPath.attr({ - 'stroke-width': 1, - 'fill': 'Black', - 'stroke': 'White' + var sendPath = drawPath(p, pathData, { + strokeWidth: 1, + fill: 'Black', + stroke: 'White' }); return task; }, 'bpmn:ReceiveTask' : function(p, data) { - var task = renderer('bpmn:Task')(p, data); + var semantic = getSemantic(data); + var task = renderer('bpmn:Task')(p, data); var pathData; - if(!!bpmnRegistry.getSemantic(data.id).instantiate) { + + if (!!semantic.instantiate) { drawCircle(p, 28, 28, 20 * 0.22); pathData = pathMap.getScaledPath('TASK_TYPE_INSTANTIATING_SEND', { @@ -807,9 +779,8 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { }); } - var sendPath = drawPath(p, pathData); - sendPath.attr({ - 'stroke-width': 1 + var sendPath = drawPath(p, pathData, { + strokeWidth: 1 }); return task; @@ -824,9 +795,8 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { } }); - var scriptPath = drawPath(p, pathData); - scriptPath.attr({ - 'stroke-width': 1 + var scriptPath = drawPath(p, pathData, { + strokeWidth: 1 }); return task; @@ -843,8 +813,8 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { var businessHeaderPath = drawPath(p, headerPathData); businessHeaderPath.attr({ - 'stroke-width': 1, - 'fill': 'AAA' + strokeWidth: 1, + fill: 'AAA' }); var headerData = pathMap.getScaledPath('TASK_TYPE_BUSINESS_RULE_MAIN', { @@ -856,27 +826,27 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { var businessPath = drawPath(p, headerData); businessPath.attr({ - 'stroke-width': 1 + strokeWidth: 1 }); return task; }, - 'bpmn:SubProcess': function(p, data) { - var rect = renderer('bpmn:Activity')(p, data); + 'bpmn:SubProcess': function(p, data, attrs) { + var rect = renderer('bpmn:Activity')(p, data, attrs); - var isEventSubProcess = !!(bpmnRegistry.getSemantic(data.id).triggeredByEvent); - if(isEventSubProcess) { + var semantic = getSemantic(data), + di = getDi(data); + + var isEventSubProcess = !!(getSemantic(data).triggeredByEvent); + if (isEventSubProcess) { rect.attr({ - 'stroke-dasharray': '1,2', - 'stroke-width': 1 + strokeDasharray: '1,2' }); } - var di = bpmnRegistry.getDi(data); - renderEmbeddedLabel(p, data, di.isExpanded ? 'center-top' : 'center-middle'); - if(di.isExpanded) { + if (di.isExpanded) { attachTaskMarkers(p, data); } else { attachTaskMarkers(p, data, ['SubProcessMarker']); @@ -889,40 +859,37 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { }, 'bpmn:Transaction': function(p, data) { var outer = renderer('bpmn:SubProcess')(p, data); - var inner = drawRect(p, data.width, data.height, TASK_BORDER_RADIUS - 2, INNER_OUTER_DIST) - .attr(styles.style([ 'no-fill', 'no-events' ])); - outer.attr('stroke-width', 1); - inner.attr('stroke-width', 1); + var innerAttrs = styles.style([ 'no-fill', 'no-events' ]); + var inner = drawRect(p, data.width, data.height, TASK_BORDER_RADIUS - 2, INNER_OUTER_DIST, innerAttrs); return outer; }, 'bpmn:CallActivity': function(p, data) { - var rect = renderer('bpmn:SubProcess')(p, data); - rect.attr('stroke-width', 4); - return rect; + return renderer('bpmn:SubProcess')(p, data, { + strokeWidth: 5 + }); }, - 'bpmn:Participant': function(p, data) { var lane = renderer('bpmn:Lane')(p, data); - var expandedPool = !!(bpmnRegistry.getSemantic(data.id).processRef); + var expandedPool = !!(getSemantic(data).processRef); if (expandedPool) { drawLine(p, [ {x: 30, y: 0}, {x: 30, y: data.height} ]); - var text = bpmnRegistry.getSemantic(data.id).name; + var text = getSemantic(data).name; renderLaneLabel(p, text, data); } else { // Collapsed pool draw text inline - var text2 = bpmnRegistry.getSemantic(data.id).name; + var text2 = getSemantic(data).name; renderLabel(p, text2, { box: data, align: 'center-middle' }); } - var participantMultiplicity = !!(bpmnRegistry.getSemantic(data.id).participantMultiplicity); + var participantMultiplicity = !!(getSemantic(data).participantMultiplicity); if(participantMultiplicity) { renderer('ParticipantMultiplicityMarker')(p, data); @@ -931,12 +898,14 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { return lane; }, 'bpmn:Lane': function(p, data) { - var rect = drawRect(p, data.width, data.height, 0); + var rect = drawRect(p, data.width, data.height, 0, { + fill: 'None' + }); - rect.attr('fill', 'None'); + var semantic = getSemantic(data); - if(bpmnRegistry.getSemantic(data.id).$type === 'bpmn:Lane') { - var text = bpmnRegistry.getSemantic(data.id).name; + if (semantic.$type === 'bpmn:Lane') { + var text = semantic.name; renderLaneLabel(p, text, data); } @@ -945,10 +914,9 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { 'bpmn:InclusiveGateway': function(p, data) { var diamond = drawDiamond(p, data.width, data.height); - var circle = drawCircle(p, data.width, data.height, data.height * 0.24); - circle.attr({ - 'stroke-width': 2.5, - 'fill': 'None' + var circle = drawCircle(p, data.width, data.height, data.height * 0.24, { + strokeWidth: 2.5, + fill: 'None' }); return diamond; @@ -967,10 +935,9 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { } }); - var exclusivePath = drawPath(p, pathData); - exclusivePath.attr({ - 'stroke-width': 1, - 'fill': 'Black' + var exclusivePath = drawPath(p, pathData, { + strokeWidth: 1, + fill: 'Black' }); return diamond; @@ -989,10 +956,9 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { } }); - var complexPath = drawPath(p, pathData); - complexPath.attr({ - 'stroke-width': 1, - 'fill': 'Black' + var complexPath = drawPath(p, pathData, { + strokeWidth: 1, + fill: 'Black' }); return diamond; @@ -1011,25 +977,26 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { } }); - var parallelPath = drawPath(p, pathData); - parallelPath.attr({ - 'stroke-width': 1, - 'fill': 'Black' + var parallelPath = drawPath(p, pathData, { + strokeWidth: 1, + fill: 'Black' }); return diamond; }, 'bpmn:EventBasedGateway': function(p, data) { + + var semantic = getSemantic(data); + var diamond = drawDiamond(p, data.width, data.height); - var outerCircle = drawCircle(p, data.width, data.height, data.height * 0.20); - outerCircle.attr({ - 'stroke-width': 1, - 'fill': 'None' + var outerCircle = drawCircle(p, data.width, data.height, data.height * 0.20, { + strokeWidth: 1, + fill: 'None' }); - var type = bpmnRegistry.getSemantic(data.id).eventGatewayType; - var instantiate = !!bpmnRegistry.getSemantic(data.id).instantiate; + var type = semantic.eventGatewayType; + var instantiate = !!semantic.instantiate; function drawEvent() { @@ -1044,14 +1011,13 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { } }); - var eventPath = drawPath(p, pathData); - eventPath.attr({ - 'stroke-width': 2, - 'fill': 'None' + var eventPath = drawPath(p, pathData, { + strokeWidth: 2, + fill: 'None' }); } - if(type === 'Parallel') { + if (type === 'Parallel') { var pathData = pathMap.getScaledPath('GATEWAY_PARALLEL', { xScaleFactor: 0.4, @@ -1066,8 +1032,8 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { var parallelPath = drawPath(p, pathData); parallelPath.attr({ - 'stroke-width': 1, - 'fill': 'None' + strokeWidth: 1, + fill: 'None' }); } else if((type === 'Exclusive') && instantiate) { @@ -1076,8 +1042,8 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { var innerCircle = drawCircle(p, data.width, data.height, data.height * 0.26); innerCircle.attr({ - 'stroke-width': 1, - 'fill': 'None' + strokeWidth: 1, + fill: 'None' }); drawEvent(); } @@ -1092,72 +1058,70 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { return diamond; }, 'bpmn:SequenceFlow': function(p, data) { - var linePathData = createPathFromWaypoints(data.waypoints); - var flowPath = drawPath(p, linePathData); + var pathData = createPathFromWaypoints(data.waypoints); + var path = drawPath(p, pathData, { + markerEnd: marker('sequenceflow-end') + }); - var sequence = bpmnRegistry.getSemantic(data.id); - var source = !!sequence.sourceRef ? bpmnRegistry.getSemantic(sequence.sourceRef) : {}; - var sourceType = source.$type; + var sequenceFlow = bpmnRegistry.getSemantic(data.id); + var source = sequenceFlow.sourceRef; - // Conditional Flow Marker - if(!!sequence.conditionExpression && - sourceType === 'bpmn:Task') { - flowPath.attr({ - 'marker-start': marker('conditional-flow-marker') + // conditional flow marker + if (sequenceFlow.conditionExpression && source.$instanceOf('bpmn:Task')) { + path.attr({ + markerStart: marker('conditional-flow-marker') }); } - // Default Marker - if(sourceType === 'bpmn:InclusiveGateway' || - sourceType === 'bpmn:ExclusiveGateway') { - - if(!!source.default && - source.default.$type === 'bpmn:SequenceFlow' && - source.default.id === data.id) { - flowPath.attr({ - 'marker-start': marker('conditional-default-flow-marker') - }); - } + // default marker + if (source.default && source.$instanceOf('bpmn:Gateway') && source.default === sequenceFlow) { + path.attr({ + markerStart: marker('conditional-default-flow-marker') + }); } - return flowPath.attr({ - 'marker-end': marker('sequenceflow-end') - }); + return path; }, 'bpmn:Association': function(p, data) { var polyline = drawLine(p, data.waypoints); // TODO(nre): style according to directed state return polyline.attr({ - 'stroke-dasharray': '3,3' + strokeDasharray: '3,3' }); }, 'bpmn:DataInputAssociation': function(p, data) { var polyline = drawLine(p, data.waypoints); return polyline.attr({ - 'stroke-dasharray': '1,4', - 'stroke-width': '1', - 'marker-end': marker('data-association-end') + strokeDasharray: '1,4', + strokeWidth: '1', + markerEnd: marker('data-association-end') }); }, 'bpmn:DataOutputAssociation': function(p, data) { var polyline = drawLine(p, data.waypoints); return polyline.attr({ - 'stroke-dasharray': '1,4', - 'stroke-width': '1', - 'marker-end': marker('data-association-end') + strokeDasharray: '1,4', + strokeWidth: '1', + markerEnd: marker('data-association-end') }); }, 'bpmn:MessageFlow': function(p, data) { - var flowDi = bpmnRegistry.getDi(data); + var di = getDi(data); - var linePathData = createPathFromWaypoints(data.waypoints); - var flowPath = drawPath(p, linePathData); - if(!!flowDi.messageVisibleKind) { - var midPoint = flowPath.getPointAtLength(flowPath.getTotalLength() / 2); + var pathData = createPathFromWaypoints(data.waypoints); + var path = drawPath(p, pathData, { + markerEnd: marker('messageflow-end'), + markerStart: marker('messageflow-start'), + strokeDasharray: '3', + strokeWidth : 1 + }); + + if (!!di.messageVisibleKind) { + var midPoint = path.getPointAtLength(path.getTotalLength() / 2); var markerPathData = pathMap.getScaledPath('MESSAGE_FLOW_MARKER', { abspos: { @@ -1165,25 +1129,23 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { y: midPoint.y } }); - var messageMarkerPath = drawPath(p, markerPathData); - var fill = flowDi.messageVisibleKind === 'initiating' ? 'White' : '#888'; - var stroke = flowDi.messageVisibleKind === 'initiating' ? 'Black' : 'White'; - messageMarkerPath.attr({ - 'stroke-width': 1, - 'fill': fill, - 'stroke': stroke - }); + var messageAttrs = { strokeWidth: 1 }; + + if (di.messageVisibleKind === 'initiating') { + messageAttrs.fill = 'White'; + messageAttrs.stroke = 'Black'; + } else { + messageAttrs.fill = '#888'; + messageAttrs.stroke = 'White'; + } + + drawPath(p, markerPathData, messageAttrs); } - return flowPath.attr({ - 'marker-end': marker('messageflow-end'), - 'marker-start': marker('messageflow-start'), - 'stroke-dasharray': '3', - 'stroke-width' : 1 - }); + return path; }, - 'bpmn:DataObjectReference': function(p, data) { + 'bpmn:DataObject': function(p, data) { var pathData = pathMap.getScaledPath('DATA_OBJECT_PATH', { xScaleFactor: 1, yScaleFactor: 1, @@ -1196,51 +1158,38 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { }); var dataObject = drawPath(p, pathData); - if(getObjectRef(data.id, 'isCollection') === true || - bpmnRegistry.getSemantic(data.id).isCollection === true) { - var yPosition = (data.height - 16) / data.height; + var semantic = getSemantic(data); - var collectionPathData = pathMap.getScaledPath('DATA_OBJECT_COLLECTION_PATH', { - xScaleFactor: 1, - yScaleFactor: 1, - containerWidth: data.width, - containerHeight: data.height, - position: { - mx: 0.451, - my: yPosition - } - }); - var collectionPath = drawPath(p, collectionPathData); - collectionPath.attr({ - 'stroke-width': 2 - }); + if (isCollection(semantic)) { + renderDataItemCollection(p, data); } return dataObject; }, + 'bpmn:DataObjectReference': as('bpmn:DataObject'), 'bpmn:DataInput': function(p, data) { var arrowPathData = pathMap.getRawPath('DATA_ARROW'); - //page - var dataObject = renderer('bpmn:DataObjectReference')(p, data); - //arrow - var dataInput = drawPath(p, arrowPathData); - dataInput.attr('stroke-width', 1); + // page + var dataObject = renderer('bpmn:DataObject')(p, data); + + // arrow + var dataInput = drawPath(p, arrowPathData, { strokeWidth: 1 }); return dataObject; }, 'bpmn:DataOutput': function(p, data) { var arrowPathData = pathMap.getRawPath('DATA_ARROW'); - //page - var dataObject = renderer('bpmn:DataObjectReference')(p, data); - //arrow - var dataInput = drawPath(p, arrowPathData); - dataInput.attr({ - 'stroke-width': 1, - 'fill': 'Black' + // page + var dataObject = renderer('bpmn:DataObject')(p, data); + + // arrow + var dataInput = drawPath(p, arrowPathData, { + strokeWidth: 1, + fill: 'Black' }); return dataObject; @@ -1257,34 +1206,39 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { } }); - var dataStore = drawPath(p, DATA_STORE_PATH); - dataStore.attr({ - 'stroke-width': 1, - 'fill': 'Black', - 'stroke-miterlimit': 4, + var dataStore = drawPath(p, DATA_STORE_PATH, { + strokeWidth: 1, + fill: 'Black', + strokeMiterlimit: 4, 'stroke-linejoin': 'miter', - 'stroke-linecap': 'butt', + strokeLinecap: 'butt', 'stroke-opacity': 1, - 'stroke': 'rgb(34, 34, 34)', - 'stroke-dasharray': 'none', + stroke: 'rgb(34, 34, 34)', + strokeDasharray: 'none', 'fill-opacity': 0 }); return dataStore; }, 'bpmn:BoundaryEvent': function(p, data) { - return renderer('bpmn:IntermediateNonInterruptingEvent')(p, data); + + var semantic = getSemantic(data), + cancel = semantic.cancelActivity; + + var outer = renderer('bpmn:Event')(p, data, cancel ? null : { strokeDasharray: '4' }); + var inner = drawCircle(p, data.width, data.height, INNER_OUTER_DIST, cancel ? null : { strokeDasharray: '5' }); + + renderEventContent(data, p); + + return outer; }, 'bpmn:Group': function(p, data) { - var group = drawRect(p, data.width, data.height, TASK_BORDER_RADIUS); - group.attr({ - 'stroke-width': 1, - 'stroke-dasharray': '8,3,1,3', - 'fill': 'None', - 'pointer-events': 'none' + return drawRect(p, data.width, data.height, TASK_BORDER_RADIUS, { + strokeWidth: 1, + strokeDasharray: '8,3,1,3', + fill: 'None', + pointerEvents: 'none' }); - - return group; }, 'label': function(p, data) { return renderExternalLabel(p, data, ''); @@ -1302,7 +1256,7 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { }); drawPath(p, textPathData); - var text = bpmnRegistry.getSemantic(data.id).text || ''; + var text = getSemantic(data).text || ''; var label = renderLabel(p, text, { box: data, align: 'left-middle' }); return label; @@ -1325,9 +1279,8 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { var markerRect = drawRect(p, 14, 14, 0); // Process marker is placed in the middle of the box // therefore fixed values can be used here - markerRect.transform('translate(' + (data.width / 2 - 7.5) + ',' + (data.height - 20) + ')'); - markerRect.attr({ - 'stroke-width': 1 + markerRect.transform('translate(' + (data.width / 2 - 7.5) + ',' + (data.height - 20) + ')').attr({ + strokeWidth: 1 }); var subProcessPath = pathMap.getScaledPath('MARKER_SUB_PROCESS', { @@ -1392,12 +1345,12 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { my: (data.height - 7) / data.height } }); - var marker = drawPath(p, loopPath); - marker.attr({ - 'stroke-width': 1, - 'fill': 'None', - 'stroke-linecap':'round', - 'stroke-miterlimit':0.5 + + drawPath(p, loopPath, { + strokeWidth: 1, + fill: 'None', + strokeLinecap: 'round', + strokeMiterlimit: 0.5 }); }, 'AdhocMarker': function(p, data, position) { @@ -1411,21 +1364,21 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { my: (data.height - 15) / data.height } }); - var marker = drawPath(p, loopPath); - marker.attr({ - 'stroke-width': 1, - 'fill': 'Black' + + drawPath(p, loopPath, { + strokeWidth: 1, + fill: 'Black' }); } }; function attachTaskMarkers(p, data, taskMarkers) { - var obj = bpmnRegistry.getSemantic(data.id); + var obj = getSemantic(data); var subprocess = _.contains(taskMarkers, 'SubProcessMarker'); var position; - if(subprocess) { + if (subprocess) { position = { seq: -21, parallel: -22, @@ -1447,22 +1400,22 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { renderer(marker)(p, data, position); }); - if(obj.$type === 'bpmn:AdHocSubProcess') { + if (obj.$type === 'bpmn:AdHocSubProcess') { renderer('AdhocMarker')(p, data, position); } - if(obj.loopCharacteristics && obj.loopCharacteristics.isSequential === undefined) { + if (obj.loopCharacteristics && obj.loopCharacteristics.isSequential === undefined) { renderer('LoopMarker')(p, data, position); return; } - if(obj.loopCharacteristics && + if (obj.loopCharacteristics && obj.loopCharacteristics.isSequential !== undefined && !obj.loopCharacteristics.isSequential) { renderer('ParallelMarker')(p, data, position); } - if(obj.loopCharacteristics && !!obj.loopCharacteristics.isSequential) { + if (obj.loopCharacteristics && !!obj.loopCharacteristics.isSequential) { renderer('SequentialMarker')(p, data, position); } - if(!!obj.isForCompensation) { + if (!!obj.isForCompensation) { renderer('CompensationMarker')(p, data, position); } } @@ -1471,6 +1424,7 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { var type = data.type; var h = handlers[type]; + /* jshint -W040 */ if (!h) { return DefaultRenderer.prototype.drawShape.apply(this, [ parent, data ]); } else { @@ -1482,6 +1436,7 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { var type = data.type; var h = handlers[type]; + /* jshint -W040 */ if (!h) { return DefaultRenderer.prototype.drawConnection.apply(this, [ parent, data ]); } else { @@ -1489,6 +1444,39 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { } } + function renderDataItemCollection(p, data) { + + var yPosition = (data.height - 16) / data.height; + + var pathData = pathMap.getScaledPath('DATA_OBJECT_COLLECTION_PATH', { + xScaleFactor: 1, + yScaleFactor: 1, + containerWidth: data.width, + containerHeight: data.height, + position: { + mx: 0.451, + my: yPosition + } + }); + + var collectionPath = drawPath(p, pathData, { + strokeWidth: 2 + }); + } + + function isCollection(element, filter) { + return element.isCollection || + (element.dataObjectRef && element.dataObjectRef.isCollection); + } + + function getDi(element) { + return bpmnRegistry.getDi(_.isString(element) ? element : element.id); + } + + function getSemantic(element) { + return bpmnRegistry.getSemantic(_.isString(element) ? element : element.id); + } + /** * Checks if eventDefinition of the given element matches with semantic type. * @@ -1515,20 +1503,6 @@ function BpmnRenderer(events, styles, bpmnRegistry, pathMap) { return (event.$type === 'bpmn:IntermediateThrowEvent') || (event.$type === 'bpmn:EndEvent'); } - /** - * - * @return {Object} returns a specified objectRef - */ - function getObjectRef(id, refName) { - var semantic = bpmnRegistry.getSemantic(id); - - if(!semantic || !semantic.dataObjectRef) { - return false; - } - - return semantic.dataObjectRef[refName]; - } - // hook onto canvas init event to initialize // connection start/end markers on paper events.on('canvas.init', function(event) {