Merge branch 'develop'
This commit is contained in:
commit
0a377250bb
|
@ -6,6 +6,13 @@ All notable changes to [bpmn-js](https://github.com/bpmn-io/bpmn-js) are documen
|
|||
|
||||
___Note:__ Yet to be released changes appear here._
|
||||
|
||||
## 6.5.0
|
||||
|
||||
* `FEAT`: prefer straight layout for sub-process connections ([#1309](https://github.com/bpmn-io/bpmn-js/pull/1309))
|
||||
* `FEAT`: move common auto-place feature to diagram-js, add BPMN-specific auto-place feature ([#1284](https://github.com/bpmn-io/bpmn-js/pull/1284))
|
||||
* `CHORE`: make bpmn-font a development dependency ([`63045bdf`](https://github.com/bpmn-io/bpmn-js/commit/63045bdfa87b9f1989a2a7a509facbeb4616acda))
|
||||
* `CHORE`: bump to `diagram-js@6.6.1`
|
||||
|
||||
## 6.4.2
|
||||
|
||||
* `CHORE`: bump to `bpmn-moddle@6.0.5`
|
||||
|
|
|
@ -12,8 +12,8 @@ import BaseViewer from './BaseViewer';
|
|||
*
|
||||
* @param {Object} [options] configuration options to pass to the viewer
|
||||
* @param {DOMElement} [options.container] the container to render the viewer in, defaults to body.
|
||||
* @param {String|Number} [options.width] the width of the viewer
|
||||
* @param {String|Number} [options.height] the height of the viewer
|
||||
* @param {string|number} [options.width] the width of the viewer
|
||||
* @param {string|number} [options.height] the height of the viewer
|
||||
* @param {Object} [options.moddleExtensions] extension packages to provide
|
||||
* @param {Array<didi.Module>} [options.modules] a list of modules to override the default modules
|
||||
* @param {Array<didi.Module>} [options.additionalModules] a list of modules to use with the default modules
|
||||
|
|
|
@ -40,8 +40,8 @@ import {
|
|||
*
|
||||
* @param {Object} [options] configuration options to pass to the viewer
|
||||
* @param {DOMElement} [options.container] the container to render the viewer in, defaults to body.
|
||||
* @param {String|Number} [options.width] the width of the viewer
|
||||
* @param {String|Number} [options.height] the height of the viewer
|
||||
* @param {string|number} [options.width] the width of the viewer
|
||||
* @param {string|number} [options.height] the height of the viewer
|
||||
* @param {Object} [options.moddleExtensions] extension packages to provide
|
||||
* @param {Array<didi.Module>} [options.modules] a list of modules to override the default modules
|
||||
* @param {Array<didi.Module>} [options.additionalModules] a list of modules to use with the default modules
|
||||
|
@ -84,8 +84,8 @@ inherits(BaseViewer, Diagram);
|
|||
*
|
||||
* You can use these events to hook into the life-cycle.
|
||||
*
|
||||
* @param {String} xml the BPMN 2.0 xml
|
||||
* @param {ModdleElement<BPMNDiagram>|String} [bpmnDiagram] BPMN diagram or id of diagram to render (if not provided, the first one will be rendered)
|
||||
* @param {string} xml the BPMN 2.0 xml
|
||||
* @param {ModdleElement<BPMNDiagram>|string} [bpmnDiagram] BPMN diagram or id of diagram to render (if not provided, the first one will be rendered)
|
||||
* @param {Function} [done] invoked with (err, warnings=[])
|
||||
*/
|
||||
BaseViewer.prototype.importXML = function(xml, bpmnDiagram, done) {
|
||||
|
@ -150,7 +150,7 @@ BaseViewer.prototype.importXML = function(xml, bpmnDiagram, done) {
|
|||
* You can use these events to hook into the life-cycle.
|
||||
*
|
||||
* @param {ModdleElement<Definitions>} definitions parsed BPMN 2.0 definitions
|
||||
* @param {ModdleElement<BPMNDiagram>|String} [bpmnDiagram] BPMN diagram or id of diagram to render (if not provided, the first one will be rendered)
|
||||
* @param {ModdleElement<BPMNDiagram>|string} [bpmnDiagram] BPMN diagram or id of diagram to render (if not provided, the first one will be rendered)
|
||||
* @param {Function} [done] invoked with (err, warnings=[])
|
||||
*/
|
||||
BaseViewer.prototype.importDefinitions = function(definitions, bpmnDiagram, done) {
|
||||
|
@ -183,7 +183,7 @@ BaseViewer.prototype.importDefinitions = function(definitions, bpmnDiagram, done
|
|||
*
|
||||
* You can use these events to hook into the life-cycle.
|
||||
*
|
||||
* @param {String|ModdleElement<BPMNDiagram>} [bpmnDiagramOrId] id or the diagram to open
|
||||
* @param {string|ModdleElement<BPMNDiagram>} [bpmnDiagramOrId] id or the diagram to open
|
||||
* @param {Function} [done] invoked with (err, warnings=[])
|
||||
*/
|
||||
BaseViewer.prototype.open = function(bpmnDiagramOrId, done) {
|
||||
|
@ -238,8 +238,8 @@ BaseViewer.prototype.open = function(bpmnDiagramOrId, done) {
|
|||
* You can use these events to hook into the life-cycle.
|
||||
*
|
||||
* @param {Object} [options] export options
|
||||
* @param {Boolean} [options.format=false] output formatted XML
|
||||
* @param {Boolean} [options.preamble=true] output preamble
|
||||
* @param {boolean} [options.format=false] output formatted XML
|
||||
* @param {boolean} [options.preamble=true] output preamble
|
||||
*
|
||||
* @param {Function} done invoked with (err, xml)
|
||||
*/
|
||||
|
@ -350,7 +350,7 @@ BaseViewer.prototype.saveSVG = function(options, done) {
|
|||
* var elementRegistry = viewer.get('elementRegistry');
|
||||
* var startEventShape = elementRegistry.get('StartEvent_1');
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {string} name
|
||||
*
|
||||
* @return {Object} diagram service instance
|
||||
*
|
||||
|
@ -432,8 +432,8 @@ BaseViewer.prototype.destroy = function() {
|
|||
*
|
||||
* Remove a previously added listener via {@link #off(event, callback)}.
|
||||
*
|
||||
* @param {String} event
|
||||
* @param {Number} [priority]
|
||||
* @param {string} event
|
||||
* @param {number} [priority]
|
||||
* @param {Function} callback
|
||||
* @param {Object} [that]
|
||||
*/
|
||||
|
@ -444,7 +444,7 @@ BaseViewer.prototype.on = function(event, priority, callback, target) {
|
|||
/**
|
||||
* De-register an event listener
|
||||
*
|
||||
* @param {String} event
|
||||
* @param {string} event
|
||||
* @param {Function} callback
|
||||
*/
|
||||
BaseViewer.prototype.off = function(event, callback) {
|
||||
|
@ -524,7 +524,7 @@ BaseViewer.prototype._init = function(container, moddle, options) {
|
|||
/**
|
||||
* Emit an event on the underlying {@link EventBus}
|
||||
*
|
||||
* @param {String} type
|
||||
* @param {string} type
|
||||
* @param {Object} event
|
||||
*
|
||||
* @return {Object} event processing result (if any)
|
||||
|
@ -593,7 +593,7 @@ function ensureUnit(val) {
|
|||
* Find BPMNDiagram in definitions by ID
|
||||
*
|
||||
* @param {ModdleElement<Definitions>} definitions
|
||||
* @param {String} diagramId
|
||||
* @param {string} diagramId
|
||||
*
|
||||
* @return {ModdleElement<BPMNDiagram>|null}
|
||||
*/
|
||||
|
|
|
@ -123,8 +123,8 @@ var initialDiagram =
|
|||
*
|
||||
* @param {Object} [options] configuration options to pass to the viewer
|
||||
* @param {DOMElement} [options.container] the container to render the viewer in, defaults to body.
|
||||
* @param {String|Number} [options.width] the width of the viewer
|
||||
* @param {String|Number} [options.height] the height of the viewer
|
||||
* @param {string|number} [options.width] the width of the viewer
|
||||
* @param {string|number} [options.height] the height of the viewer
|
||||
* @param {Object} [options.moddleExtensions] extension packages to provide
|
||||
* @param {Array<didi.Module>} [options.modules] a list of modules to override the default modules
|
||||
* @param {Array<didi.Module>} [options.additionalModules] a list of modules to use with the default modules
|
||||
|
|
|
@ -49,8 +49,8 @@ import BaseViewer from './BaseViewer';
|
|||
*
|
||||
* @param {Object} [options] configuration options to pass to the viewer
|
||||
* @param {DOMElement} [options.container] the container to render the viewer in, defaults to body.
|
||||
* @param {String|Number} [options.width] the width of the viewer
|
||||
* @param {String|Number} [options.height] the height of the viewer
|
||||
* @param {string|number} [options.width] the width of the viewer
|
||||
* @param {string|number} [options.height] the height of the viewer
|
||||
* @param {Object} [options.moddleExtensions] extension packages to provide
|
||||
* @param {Array<didi.Module>} [options.modules] a list of modules to override the default modules
|
||||
* @param {Array<didi.Module>} [options.additionalModules] a list of modules to use with the default modules
|
||||
|
|
|
@ -362,7 +362,7 @@ export default function PathMap() {
|
|||
* 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 {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>
|
||||
|
|
|
@ -32,7 +32,7 @@ export default function TextRenderer(config) {
|
|||
* layouted label.
|
||||
*
|
||||
* @param {Bounds} bounds
|
||||
* @param {String} text
|
||||
* @param {string} text
|
||||
*
|
||||
* @return {Bounds}
|
||||
*/
|
||||
|
@ -62,7 +62,7 @@ export default function TextRenderer(config) {
|
|||
* Get the new bounds of text annotation.
|
||||
*
|
||||
* @param {Bounds} bounds
|
||||
* @param {String} text
|
||||
* @param {string} text
|
||||
*
|
||||
* @return {Bounds}
|
||||
*/
|
||||
|
@ -86,7 +86,7 @@ export default function TextRenderer(config) {
|
|||
/**
|
||||
* Create a layouted text element.
|
||||
*
|
||||
* @param {String} text
|
||||
* @param {string} text
|
||||
* @param {Object} [options]
|
||||
*
|
||||
* @return {SVGElement} rendered text
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
import { getNewShapePosition } from './AutoPlaceUtil';
|
||||
|
||||
|
||||
/**
|
||||
* A service that places elements connected to existing ones
|
||||
* to an appropriate position in an _automated_ fashion.
|
||||
*
|
||||
* @param {EventBus} eventBus
|
||||
* @param {Modeling} modeling
|
||||
*/
|
||||
export default function AutoPlace(eventBus, modeling) {
|
||||
|
||||
function emit(event, payload) {
|
||||
return eventBus.fire(event, payload);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Append shape to source at appropriate position.
|
||||
*
|
||||
* @param {djs.model.Shape} source
|
||||
* @param {djs.model.Shape} shape
|
||||
*
|
||||
* @return {djs.model.Shape} appended shape
|
||||
*/
|
||||
this.append = function(source, shape) {
|
||||
|
||||
emit('autoPlace.start', {
|
||||
source: source,
|
||||
shape: shape
|
||||
});
|
||||
|
||||
// allow others to provide the position
|
||||
var position = emit('autoPlace', {
|
||||
source: source,
|
||||
shape: shape
|
||||
});
|
||||
|
||||
if (!position) {
|
||||
position = getNewShapePosition(source, shape);
|
||||
}
|
||||
|
||||
var newShape = modeling.appendShape(source, shape, position, source.parent);
|
||||
|
||||
emit('autoPlace.end', {
|
||||
source: source,
|
||||
shape: newShape
|
||||
});
|
||||
|
||||
return newShape;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
AutoPlace.$inject = [
|
||||
'eventBus',
|
||||
'modeling'
|
||||
];
|
|
@ -1,18 +0,0 @@
|
|||
/**
|
||||
* Select element after auto placement.
|
||||
*
|
||||
* @param {EventBus} eventBus
|
||||
* @param {Selection} selection
|
||||
*/
|
||||
export default function AutoPlaceSelectionBehavior(eventBus, selection) {
|
||||
|
||||
eventBus.on('autoPlace.end', 500, function(e) {
|
||||
selection.select(e.shape);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
AutoPlaceSelectionBehavior.$inject = [
|
||||
'eventBus',
|
||||
'selection'
|
||||
];
|
|
@ -1,430 +0,0 @@
|
|||
import { is } from '../../util/ModelUtil';
|
||||
import { isAny } from '../modeling/util/ModelingUtil';
|
||||
|
||||
import {
|
||||
getMid,
|
||||
asTRBL,
|
||||
getOrientation
|
||||
} from 'diagram-js/lib/layout/LayoutUtil';
|
||||
|
||||
import {
|
||||
find,
|
||||
reduce
|
||||
} from 'min-dash';
|
||||
|
||||
var DEFAULT_HORIZONTAL_DISTANCE = 50;
|
||||
|
||||
var MAX_HORIZONTAL_DISTANCE = 250;
|
||||
|
||||
// padding to detect element placement
|
||||
var PLACEMENT_DETECTION_PAD = 10;
|
||||
|
||||
/**
|
||||
* Find the new position for the target element to
|
||||
* connect to source.
|
||||
*
|
||||
* @param {djs.model.Shape} source
|
||||
* @param {djs.model.Shape} element
|
||||
*
|
||||
* @return {Point}
|
||||
*/
|
||||
export function getNewShapePosition(source, element) {
|
||||
|
||||
if (is(element, 'bpmn:TextAnnotation')) {
|
||||
return getTextAnnotationPosition(source, element);
|
||||
}
|
||||
|
||||
if (isAny(element, [ 'bpmn:DataObjectReference', 'bpmn:DataStoreReference' ])) {
|
||||
return getDataElementPosition(source, element);
|
||||
}
|
||||
|
||||
if (is(element, 'bpmn:FlowNode')) {
|
||||
return getFlowNodePosition(source, element);
|
||||
}
|
||||
|
||||
return getDefaultPosition(source, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Always try to place element right of source;
|
||||
* compute actual distance from previous nodes in flow.
|
||||
*/
|
||||
export function getFlowNodePosition(source, element) {
|
||||
|
||||
var sourceTrbl = asTRBL(source);
|
||||
var sourceMid = getMid(source);
|
||||
|
||||
var horizontalDistance = getFlowNodeDistance(source, element);
|
||||
|
||||
var orientation = 'left',
|
||||
rowSize = 80,
|
||||
margin = 30;
|
||||
|
||||
if (is(source, 'bpmn:BoundaryEvent')) {
|
||||
orientation = getOrientation(source, source.host, -25);
|
||||
|
||||
if (orientation.indexOf('top') !== -1) {
|
||||
margin *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
function getVerticalDistance(orient) {
|
||||
if (orient.indexOf('top') != -1) {
|
||||
return -1 * rowSize;
|
||||
} else if (orient.indexOf('bottom') != -1) {
|
||||
return rowSize;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
var position = {
|
||||
x: sourceTrbl.right + horizontalDistance + element.width / 2,
|
||||
y: sourceMid.y + getVerticalDistance(orientation)
|
||||
};
|
||||
|
||||
var escapeDirection = {
|
||||
y: {
|
||||
margin: margin,
|
||||
rowSize: rowSize
|
||||
}
|
||||
};
|
||||
|
||||
return deconflictPosition(source, element, position, escapeDirection);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compute best distance between source and target,
|
||||
* based on existing connections to and from source.
|
||||
*
|
||||
* @param {djs.model.Shape} source
|
||||
* @param {djs.model.Shape} element
|
||||
*
|
||||
* @return {Number} distance
|
||||
*/
|
||||
export function getFlowNodeDistance(source, element) {
|
||||
|
||||
var sourceTrbl = asTRBL(source);
|
||||
|
||||
// is connection a reference to consider?
|
||||
function isReference(c) {
|
||||
return is(c, 'bpmn:SequenceFlow');
|
||||
}
|
||||
|
||||
function toTargetNode(weight) {
|
||||
|
||||
return function(shape) {
|
||||
return {
|
||||
shape: shape,
|
||||
weight: weight,
|
||||
distanceTo: function(shape) {
|
||||
var shapeTrbl = asTRBL(shape);
|
||||
|
||||
return shapeTrbl.left - sourceTrbl.right;
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
function toSourceNode(weight) {
|
||||
return function(shape) {
|
||||
return {
|
||||
shape: shape,
|
||||
weight: weight,
|
||||
distanceTo: function(shape) {
|
||||
var shapeTrbl = asTRBL(shape);
|
||||
|
||||
return sourceTrbl.left - shapeTrbl.right;
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// we create a list of nodes to take into consideration
|
||||
// for calculating the optimal flow node distance
|
||||
//
|
||||
// * weight existing target nodes higher than source nodes
|
||||
// * only take into account individual nodes once
|
||||
//
|
||||
var nodes = reduce([].concat(
|
||||
getTargets(source, isReference).map(toTargetNode(5)),
|
||||
getSources(source, isReference).map(toSourceNode(1))
|
||||
), function(nodes, node) {
|
||||
|
||||
// filter out shapes connected twice via source or target
|
||||
nodes[node.shape.id + '__weight_' + node.weight] = node;
|
||||
|
||||
return nodes;
|
||||
}, {});
|
||||
|
||||
// compute distances between source and incoming nodes;
|
||||
// group at the same time by distance and expose the
|
||||
// favourite distance as { fav: { count, value } }.
|
||||
var distancesGrouped = reduce(nodes, function(result, node) {
|
||||
|
||||
var shape = node.shape,
|
||||
weight = node.weight,
|
||||
distanceTo = node.distanceTo;
|
||||
|
||||
var fav = result.fav,
|
||||
currentDistance,
|
||||
currentDistanceCount,
|
||||
currentDistanceEntry;
|
||||
|
||||
currentDistance = distanceTo(shape);
|
||||
|
||||
// ignore too far away peers
|
||||
// or non-left to right modeled nodes
|
||||
if (currentDistance < 0 || currentDistance > MAX_HORIZONTAL_DISTANCE) {
|
||||
return result;
|
||||
}
|
||||
|
||||
currentDistanceEntry = result[String(currentDistance)] =
|
||||
result[String(currentDistance)] || {
|
||||
value: currentDistance,
|
||||
count: 0
|
||||
};
|
||||
|
||||
// inc diff count
|
||||
currentDistanceCount = currentDistanceEntry.count += 1 * weight;
|
||||
|
||||
if (!fav || fav.count < currentDistanceCount) {
|
||||
result.fav = currentDistanceEntry;
|
||||
}
|
||||
|
||||
return result;
|
||||
}, { });
|
||||
|
||||
|
||||
if (distancesGrouped.fav) {
|
||||
return distancesGrouped.fav.value;
|
||||
} else {
|
||||
return DEFAULT_HORIZONTAL_DISTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Always try to place text annotations top right of source.
|
||||
*/
|
||||
export function getTextAnnotationPosition(source, element) {
|
||||
|
||||
var sourceTrbl = asTRBL(source);
|
||||
|
||||
var position = {
|
||||
x: sourceTrbl.right + element.width / 2,
|
||||
y: sourceTrbl.top - 50 - element.height / 2
|
||||
};
|
||||
|
||||
var escapeDirection = {
|
||||
y: {
|
||||
margin: -30,
|
||||
rowSize: 20
|
||||
}
|
||||
};
|
||||
|
||||
return deconflictPosition(source, element, position, escapeDirection);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Always put element bottom right of source.
|
||||
*/
|
||||
export function getDataElementPosition(source, element) {
|
||||
|
||||
var sourceTrbl = asTRBL(source);
|
||||
|
||||
var position = {
|
||||
x: sourceTrbl.right - 10 + element.width / 2,
|
||||
y: sourceTrbl.bottom + 40 + element.width / 2
|
||||
};
|
||||
|
||||
var escapeDirection = {
|
||||
x: {
|
||||
margin: 30,
|
||||
rowSize: 30
|
||||
}
|
||||
};
|
||||
|
||||
return deconflictPosition(source, element, position, escapeDirection);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Always put element right of source per default.
|
||||
*/
|
||||
export function getDefaultPosition(source, element) {
|
||||
|
||||
var sourceTrbl = asTRBL(source);
|
||||
|
||||
var sourceMid = getMid(source);
|
||||
|
||||
// simply put element right next to source
|
||||
return {
|
||||
x: sourceTrbl.right + DEFAULT_HORIZONTAL_DISTANCE + element.width / 2,
|
||||
y: sourceMid.y
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns all connected elements around the given source.
|
||||
*
|
||||
* This includes:
|
||||
*
|
||||
* - connected elements
|
||||
* - host connected elements
|
||||
* - attachers connected elements
|
||||
*
|
||||
* @param {djs.model.Shape} source
|
||||
* @param {djs.model.Shape} element
|
||||
*
|
||||
* @return {Array<djs.model.Shape>}
|
||||
*/
|
||||
function getAutoPlaceClosure(source, element) {
|
||||
|
||||
var allConnected = getConnected(source);
|
||||
|
||||
if (source.host) {
|
||||
allConnected = allConnected.concat(getConnected(source.host));
|
||||
}
|
||||
|
||||
if (source.attachers) {
|
||||
allConnected = allConnected.concat(source.attachers.reduce(function(shapes, attacher) {
|
||||
return shapes.concat(getConnected(attacher));
|
||||
}, []));
|
||||
}
|
||||
|
||||
return allConnected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return target at given position, if defined.
|
||||
*
|
||||
* This takes connected elements from host and attachers
|
||||
* into account, too.
|
||||
*/
|
||||
export function getConnectedAtPosition(source, position, element) {
|
||||
|
||||
var bounds = {
|
||||
x: position.x - (element.width / 2),
|
||||
y: position.y - (element.height / 2),
|
||||
width: element.width,
|
||||
height: element.height
|
||||
};
|
||||
|
||||
var closure = getAutoPlaceClosure(source, element);
|
||||
|
||||
return find(closure, function(target) {
|
||||
|
||||
if (target === element) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var orientation = getOrientation(target, bounds, PLACEMENT_DETECTION_PAD);
|
||||
|
||||
return orientation === 'intersect';
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a new, position for the given element
|
||||
* based on the given element that is not occupied
|
||||
* by some element connected to source.
|
||||
*
|
||||
* Take into account the escapeDirection (where to move
|
||||
* on positioning clashes) in the computation.
|
||||
*
|
||||
* @param {djs.model.Shape} source
|
||||
* @param {djs.model.Shape} element
|
||||
* @param {Point} position
|
||||
* @param {Object} escapeDelta
|
||||
*
|
||||
* @return {Point}
|
||||
*/
|
||||
export function deconflictPosition(source, element, position, escapeDelta) {
|
||||
|
||||
function nextPosition(existingElement) {
|
||||
|
||||
var newPosition = {
|
||||
x: position.x,
|
||||
y: position.y
|
||||
};
|
||||
|
||||
[ 'x', 'y' ].forEach(function(axis) {
|
||||
|
||||
var axisDelta = escapeDelta[axis];
|
||||
|
||||
if (!axisDelta) {
|
||||
return;
|
||||
}
|
||||
|
||||
var dimension = axis === 'x' ? 'width' : 'height';
|
||||
|
||||
var margin = axisDelta.margin,
|
||||
rowSize = axisDelta.rowSize;
|
||||
|
||||
if (margin < 0) {
|
||||
newPosition[axis] = Math.min(
|
||||
existingElement[axis] + margin - element[dimension] / 2,
|
||||
position[axis] - rowSize + margin
|
||||
);
|
||||
} else {
|
||||
newPosition[axis] = Math.max(
|
||||
existingTarget[axis] + existingTarget[dimension] + margin + element[dimension] / 2,
|
||||
position[axis] + rowSize + margin
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return newPosition;
|
||||
}
|
||||
|
||||
var existingTarget;
|
||||
|
||||
// deconflict position until free slot is found
|
||||
while ((existingTarget = getConnectedAtPosition(source, position, element))) {
|
||||
position = nextPosition(existingTarget);
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// helpers //////////////////////
|
||||
|
||||
function noneFilter() {
|
||||
return true;
|
||||
}
|
||||
|
||||
function getConnected(element, connectionFilter) {
|
||||
return [].concat(
|
||||
getTargets(element, connectionFilter),
|
||||
getSources(element, connectionFilter)
|
||||
);
|
||||
}
|
||||
|
||||
function getSources(shape, connectionFilter) {
|
||||
|
||||
if (!connectionFilter) {
|
||||
connectionFilter = noneFilter;
|
||||
}
|
||||
|
||||
return shape.incoming.filter(connectionFilter).map(function(c) {
|
||||
return c.source;
|
||||
});
|
||||
}
|
||||
|
||||
function getTargets(shape, connectionFilter) {
|
||||
|
||||
if (!connectionFilter) {
|
||||
connectionFilter = noneFilter;
|
||||
}
|
||||
|
||||
return shape.outgoing.filter(connectionFilter).map(function(c) {
|
||||
return c.target;
|
||||
});
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
import { getNewShapePosition } from './BpmnAutoPlaceUtil';
|
||||
|
||||
|
||||
/**
|
||||
* BPMN auto-place behavior.
|
||||
*
|
||||
* @param {EventBus} eventBus
|
||||
*/
|
||||
export default function AutoPlace(eventBus) {
|
||||
eventBus.on('autoPlace', function(context) {
|
||||
var shape = context.shape,
|
||||
source = context.source;
|
||||
|
||||
return getNewShapePosition(source, shape);
|
||||
});
|
||||
}
|
||||
|
||||
AutoPlace.$inject = [ 'eventBus' ];
|
|
@ -0,0 +1,138 @@
|
|||
import { is } from '../../util/ModelUtil';
|
||||
import { isAny } from '../modeling/util/ModelingUtil';
|
||||
|
||||
import {
|
||||
getMid,
|
||||
asTRBL,
|
||||
getOrientation
|
||||
} from 'diagram-js/lib/layout/LayoutUtil';
|
||||
|
||||
import {
|
||||
findFreePosition,
|
||||
generateGetNextPosition,
|
||||
getConnectedDistance
|
||||
} from 'diagram-js/lib/features/auto-place/AutoPlaceUtil';
|
||||
|
||||
|
||||
/**
|
||||
* Find the new position for the target element to
|
||||
* connect to source.
|
||||
*
|
||||
* @param {djs.model.Shape} source
|
||||
* @param {djs.model.Shape} element
|
||||
*
|
||||
* @return {Point}
|
||||
*/
|
||||
export function getNewShapePosition(source, element) {
|
||||
|
||||
if (is(element, 'bpmn:TextAnnotation')) {
|
||||
return getTextAnnotationPosition(source, element);
|
||||
}
|
||||
|
||||
if (isAny(element, [ 'bpmn:DataObjectReference', 'bpmn:DataStoreReference' ])) {
|
||||
return getDataElementPosition(source, element);
|
||||
}
|
||||
|
||||
if (is(element, 'bpmn:FlowNode')) {
|
||||
return getFlowNodePosition(source, element);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Always try to place element right of source;
|
||||
* compute actual distance from previous nodes in flow.
|
||||
*/
|
||||
export function getFlowNodePosition(source, element) {
|
||||
|
||||
var sourceTrbl = asTRBL(source);
|
||||
var sourceMid = getMid(source);
|
||||
|
||||
var horizontalDistance = getConnectedDistance(source, {
|
||||
filter: function(connection) {
|
||||
return is(connection, 'bpmn:SequenceFlow');
|
||||
}
|
||||
});
|
||||
|
||||
var margin = 30,
|
||||
minDistance = 80,
|
||||
orientation = 'left';
|
||||
|
||||
if (is(source, 'bpmn:BoundaryEvent')) {
|
||||
orientation = getOrientation(source, source.host, -25);
|
||||
|
||||
if (orientation.indexOf('top') !== -1) {
|
||||
margin *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
var position = {
|
||||
x: sourceTrbl.right + horizontalDistance + element.width / 2,
|
||||
y: sourceMid.y + getVerticalDistance(orientation, minDistance)
|
||||
};
|
||||
|
||||
var nextPositionDirection = {
|
||||
y: {
|
||||
margin: margin,
|
||||
minDistance: minDistance
|
||||
}
|
||||
};
|
||||
|
||||
return findFreePosition(source, element, position, generateGetNextPosition(nextPositionDirection));
|
||||
}
|
||||
|
||||
|
||||
function getVerticalDistance(orientation, minDistance) {
|
||||
if (orientation.indexOf('top') != -1) {
|
||||
return -1 * minDistance;
|
||||
} else if (orientation.indexOf('bottom') != -1) {
|
||||
return minDistance;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Always try to place text annotations top right of source.
|
||||
*/
|
||||
export function getTextAnnotationPosition(source, element) {
|
||||
|
||||
var sourceTrbl = asTRBL(source);
|
||||
|
||||
var position = {
|
||||
x: sourceTrbl.right + element.width / 2,
|
||||
y: sourceTrbl.top - 50 - element.height / 2
|
||||
};
|
||||
|
||||
var nextPositionDirection = {
|
||||
y: {
|
||||
margin: -30,
|
||||
minDistance: 20
|
||||
}
|
||||
};
|
||||
|
||||
return findFreePosition(source, element, position, generateGetNextPosition(nextPositionDirection));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Always put element bottom right of source.
|
||||
*/
|
||||
export function getDataElementPosition(source, element) {
|
||||
|
||||
var sourceTrbl = asTRBL(source);
|
||||
|
||||
var position = {
|
||||
x: sourceTrbl.right - 10 + element.width / 2,
|
||||
y: sourceTrbl.bottom + 40 + element.width / 2
|
||||
};
|
||||
|
||||
var nextPositionDirection = {
|
||||
x: {
|
||||
margin: 30,
|
||||
minDistance: 30
|
||||
}
|
||||
};
|
||||
|
||||
return findFreePosition(source, element, position, generateGetNextPosition(nextPositionDirection));
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
import AutoPlace from './AutoPlace';
|
||||
import AutoPlaceSelectionBehavior from './AutoPlaceSelectionBehavior';
|
||||
import AutoPlaceModule from 'diagram-js/lib/features/auto-place';
|
||||
|
||||
import BpmnAutoPlace from './BpmnAutoPlace';
|
||||
|
||||
export default {
|
||||
__init__: [ 'autoPlaceSelectionBehavior' ],
|
||||
autoPlace: [ 'type', AutoPlace ],
|
||||
autoPlaceSelectionBehavior: [ 'type', AutoPlaceSelectionBehavior ]
|
||||
__depends__: [ AutoPlaceModule ],
|
||||
__init__: [ 'bpmnAutoPlace' ],
|
||||
bpmnAutoPlace: [ 'type', BpmnAutoPlace ]
|
||||
};
|
|
@ -142,9 +142,9 @@ ContextPadProvider.prototype.getContextPadEntries = function(element) {
|
|||
/**
|
||||
* Create an append action
|
||||
*
|
||||
* @param {String} type
|
||||
* @param {String} className
|
||||
* @param {String} [title]
|
||||
* @param {string} type
|
||||
* @param {string} className
|
||||
* @param {string} [title]
|
||||
* @param {Object} [options]
|
||||
*
|
||||
* @return {Object} descriptor
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import { getNewShapePosition } from '../../auto-place/AutoPlaceUtil';
|
||||
import { getNewShapePosition } from '../../auto-place/BpmnAutoPlaceUtil';
|
||||
|
||||
import { getMid } from 'diagram-js/lib/layout/LayoutUtil';
|
||||
import { is } from '../../../util/ModelUtil';
|
||||
|
||||
var HIGH_PRIORITY = 2000;
|
||||
|
||||
|
||||
export default function AutoPlaceBehavior(eventBus, gridSnapping) {
|
||||
eventBus.on('autoPlace', function(context) {
|
||||
eventBus.on('autoPlace', HIGH_PRIORITY, function(context) {
|
||||
var source = context.source,
|
||||
sourceMid = getMid(source),
|
||||
shape = context.shape;
|
||||
|
|
|
@ -34,7 +34,7 @@ BpmnKeyboardBindings.prototype.registerBindings = function(keyboard, editorActio
|
|||
* Add keyboard binding if respective editor action
|
||||
* is registered.
|
||||
*
|
||||
* @param {String} action name
|
||||
* @param {string} action name
|
||||
* @param {Function} fn that implements the key binding
|
||||
*/
|
||||
function addListener(action, fn) {
|
||||
|
|
|
@ -31,7 +31,7 @@ export default function UpdateLabelHandler(modeling, textRenderer) {
|
|||
* Element parameter can be label itself or connection (i.e. sequence flow).
|
||||
*
|
||||
* @param {djs.model.Base} element
|
||||
* @param {String} text
|
||||
* @param {string} text
|
||||
*/
|
||||
function setText(element, text) {
|
||||
|
||||
|
|
|
@ -98,6 +98,8 @@ BpmnLayouter.prototype.layoutConnection = function(connection, hints) {
|
|||
manhattanOptions = {
|
||||
preferredLayouts: getBoundaryEventPreferredLayouts(source, target, connectionEnd)
|
||||
};
|
||||
} else if (isExpandedSubProcess(source) || isExpandedSubProcess(target)) {
|
||||
manhattanOptions = getSubProcessManhattanOptions(source);
|
||||
} else if (is(source, 'bpmn:Gateway')) {
|
||||
manhattanOptions = {
|
||||
preferredLayouts: [ 'v:h' ]
|
||||
|
@ -177,6 +179,17 @@ function getMessageFlowPreserveDocking(source, target) {
|
|||
return null;
|
||||
}
|
||||
|
||||
function getSubProcessManhattanOptions(source) {
|
||||
return {
|
||||
preferredLayouts: [ 'straight', 'h:h' ],
|
||||
preserveDocking: getSubProcessPreserveDocking(source)
|
||||
};
|
||||
}
|
||||
|
||||
function getSubProcessPreserveDocking(source) {
|
||||
return isExpandedSubProcess(source) ? 'target' : 'source';
|
||||
}
|
||||
|
||||
function getConnectionDocking(point, shape) {
|
||||
return point ? (point.original || point) : getMid(shape);
|
||||
}
|
||||
|
|
|
@ -229,7 +229,7 @@ ElementFactory.prototype.createParticipantShape = function(attrs) {
|
|||
*
|
||||
* @param {Base} element
|
||||
* @param {Object} attrs (in/out map of attributes)
|
||||
* @param {Array<String>} attributeNames name of attributes to apply
|
||||
* @param {Array<string>} attributeNames name of attributes to apply
|
||||
*/
|
||||
function applyAttributes(element, attrs, attributeNames) {
|
||||
|
||||
|
@ -246,7 +246,7 @@ function applyAttributes(element, attrs, attributeNames) {
|
|||
*
|
||||
* @param {Base} element
|
||||
* @param {Object} attrs (in/out map of attributes)
|
||||
* @param {String} attributeName to apply
|
||||
* @param {string} attributeName to apply
|
||||
*/
|
||||
function applyAttribute(element, attrs, attributeName) {
|
||||
element[attributeName] = attrs[attributeName];
|
||||
|
|
|
@ -173,7 +173,7 @@ AdaptiveLabelPositioningBehavior.$inject = [
|
|||
*
|
||||
* @param {Shape} element
|
||||
*
|
||||
* @return {Array<String>}
|
||||
* @return {Array<string>}
|
||||
*/
|
||||
function getTakenHostAlignments(element) {
|
||||
|
||||
|
@ -204,7 +204,7 @@ function getTakenHostAlignments(element) {
|
|||
*
|
||||
* @param {Shape} element
|
||||
*
|
||||
* @return {Array<String>}
|
||||
* @return {Array<string>}
|
||||
*/
|
||||
function getTakenConnectionAlignments(element) {
|
||||
|
||||
|
@ -230,7 +230,7 @@ function getTakenConnectionAlignments(element) {
|
|||
*
|
||||
* @param {Shape} element
|
||||
*
|
||||
* @return {String} positioning identifier
|
||||
* @return {string} positioning identifier
|
||||
*/
|
||||
function getOptimalPosition(element) {
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ export default function GroupBehavior(
|
|||
*
|
||||
* @param {Array<djs.model.shape>} elements
|
||||
* @param {ModdleElement} categoryValue
|
||||
* @return {Boolean}
|
||||
* @return {boolean}
|
||||
*/
|
||||
function isReferenced(elements, categoryValue) {
|
||||
return elements.some(function(e) {
|
||||
|
|
|
@ -6,6 +6,8 @@ import { getParticipantResizeConstraints } from './util/ResizeUtil';
|
|||
|
||||
var HIGH_PRIORITY = 1500;
|
||||
|
||||
export var LANE_MIN_DIMENSIONS = { width: 300, height: 60 };
|
||||
|
||||
export var PARTICIPANT_MIN_DIMENSIONS = { width: 300, height: 150 };
|
||||
|
||||
export var SUB_PROCESS_MIN_DIMENSIONS = { width: 140, height: 120 };
|
||||
|
|
|
@ -5,21 +5,38 @@ import { is } from '../../../util/ModelUtil';
|
|||
import { isExpanded } from '../../../util/DiUtil';
|
||||
|
||||
import {
|
||||
LANE_MIN_DIMENSIONS,
|
||||
PARTICIPANT_MIN_DIMENSIONS,
|
||||
SUB_PROCESS_MIN_DIMENSIONS,
|
||||
TEXT_ANNOTATION_MIN_DIMENSIONS
|
||||
} from './ResizeBehavior';
|
||||
|
||||
import { getChildLanes } from '../util/LaneUtil';
|
||||
|
||||
var max = Math.max;
|
||||
|
||||
|
||||
export default function SpaceToolBehavior(eventBus) {
|
||||
eventBus.on('spaceTool.getMinDimensions', function(context) {
|
||||
var shapes = context.shapes,
|
||||
axis = context.axis,
|
||||
start = context.start,
|
||||
minDimensions = {};
|
||||
|
||||
forEach(shapes, function(shape) {
|
||||
var id = shape.id;
|
||||
|
||||
if (is(shape, 'bpmn:Participant')) {
|
||||
minDimensions[ id ] = PARTICIPANT_MIN_DIMENSIONS;
|
||||
|
||||
if (isHorizontal(axis)) {
|
||||
minDimensions[ id ] = PARTICIPANT_MIN_DIMENSIONS;
|
||||
} else {
|
||||
minDimensions[ id ] = {
|
||||
width: PARTICIPANT_MIN_DIMENSIONS.width,
|
||||
height: getParticipantMinHeight(shape, start)
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (is(shape, 'bpmn:SubProcess') && isExpanded(shape)) {
|
||||
|
@ -36,3 +53,72 @@ export default function SpaceToolBehavior(eventBus) {
|
|||
}
|
||||
|
||||
SpaceToolBehavior.$inject = [ 'eventBus' ];
|
||||
|
||||
|
||||
// helpers //////////
|
||||
function isHorizontal(axis) {
|
||||
return axis === 'x';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get minimum height for participant taking lanes into account.
|
||||
*
|
||||
* @param {<djs.model.Shape>} participant
|
||||
* @param {number} start
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
function getParticipantMinHeight(participant, start) {
|
||||
var lanesMinHeight;
|
||||
|
||||
if (!hasChildLanes(participant)) {
|
||||
return PARTICIPANT_MIN_DIMENSIONS.height;
|
||||
}
|
||||
|
||||
lanesMinHeight = getLanesMinHeight(participant, start);
|
||||
|
||||
return max(PARTICIPANT_MIN_DIMENSIONS.height, lanesMinHeight);
|
||||
}
|
||||
|
||||
function hasChildLanes(element) {
|
||||
return !!getChildLanes(element).length;
|
||||
}
|
||||
|
||||
function getLanesMinHeight(participant, resizeStart) {
|
||||
var lanes = getChildLanes(participant),
|
||||
resizedLane;
|
||||
|
||||
// find the nested lane which is currently resized
|
||||
resizedLane = findResizedLane(lanes, resizeStart);
|
||||
|
||||
// resized lane cannot shrink below the minimum height
|
||||
// but remaining lanes' dimensions are kept intact
|
||||
return participant.height - resizedLane.height + LANE_MIN_DIMENSIONS.height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find nested lane which is currently resized.
|
||||
*
|
||||
* @param {Array<djs.model.Shape>} lanes
|
||||
* @param {number} resizeStart
|
||||
*/
|
||||
function findResizedLane(lanes, resizeStart) {
|
||||
var i, lane, childLanes;
|
||||
|
||||
for (i = 0; i < lanes.length; i++) {
|
||||
lane = lanes[i];
|
||||
|
||||
// resizing current lane or a lane nested
|
||||
if (resizeStart >= lane.y && resizeStart <= lane.y + lane.height) {
|
||||
childLanes = getChildLanes(lane);
|
||||
|
||||
// a nested lane is resized
|
||||
if (childLanes.length) {
|
||||
return findResizedLane(childLanes, resizeStart);
|
||||
}
|
||||
|
||||
// current lane is the resized one
|
||||
return lane;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ var sqrt = Math.sqrt,
|
|||
/**
|
||||
* Calculate the square (power to two) of a number.
|
||||
*
|
||||
* @param {Number} n
|
||||
* @param {number} n
|
||||
*
|
||||
* @return {Number}
|
||||
* @return {number}
|
||||
*/
|
||||
function sq(n) {
|
||||
return Math.pow(n, 2);
|
||||
|
@ -20,7 +20,7 @@ function sq(n) {
|
|||
* @param {Point} p1
|
||||
* @param {Point} p2
|
||||
*
|
||||
* @return {Number}
|
||||
* @return {number}
|
||||
*/
|
||||
function getDistance(p1, p2) {
|
||||
return sqrt(sq(p1.x - p2.x) + sq(p1.y - p2.y));
|
||||
|
@ -127,7 +127,7 @@ export function getAttachment(point, line) {
|
|||
* @param {Point} s1 segment start
|
||||
* @param {Point} s2 segment end
|
||||
* @param {Point} cc circle center
|
||||
* @param {Number} cr circle radius
|
||||
* @param {number} cr circle radius
|
||||
*
|
||||
* @return {Array<Point>} intersections
|
||||
*/
|
||||
|
|
|
@ -9,6 +9,8 @@ import {
|
|||
getLanesRoot
|
||||
} from '../../../modeling/util/LaneUtil';
|
||||
|
||||
import { LANE_MIN_DIMENSIONS } from '../ResizeBehavior';
|
||||
|
||||
var abs = Math.abs,
|
||||
min = Math.min,
|
||||
max = Math.max;
|
||||
|
@ -31,9 +33,7 @@ function addMax(trbl, attr, value) {
|
|||
return addToTrbl(trbl, attr, value, max);
|
||||
}
|
||||
|
||||
var LANE_MIN_HEIGHT = 60,
|
||||
LANE_MIN_WIDTH = 300,
|
||||
LANE_RIGHT_PADDING = 20,
|
||||
var LANE_RIGHT_PADDING = 20,
|
||||
LANE_LEFT_PADDING = 50,
|
||||
LANE_TOP_PADDING = 20,
|
||||
LANE_BOTTOM_PADDING = 20;
|
||||
|
@ -54,10 +54,10 @@ export function getParticipantResizeConstraints(laneShape, resizeDirection, bala
|
|||
minTrbl = {};
|
||||
|
||||
if (/e/.test(resizeDirection)) {
|
||||
minTrbl.right = laneTrbl.left + LANE_MIN_WIDTH;
|
||||
minTrbl.right = laneTrbl.left + LANE_MIN_DIMENSIONS.width;
|
||||
} else
|
||||
if (/w/.test(resizeDirection)) {
|
||||
minTrbl.left = laneTrbl.right - LANE_MIN_WIDTH;
|
||||
minTrbl.left = laneTrbl.right - LANE_MIN_DIMENSIONS.width;
|
||||
}
|
||||
|
||||
allLanes.forEach(function(other) {
|
||||
|
@ -72,12 +72,12 @@ export function getParticipantResizeConstraints(laneShape, resizeDirection, bala
|
|||
|
||||
// max top size (based on next element)
|
||||
if (balanced && abs(laneTrbl.top - otherTrbl.bottom) < 10) {
|
||||
addMax(maxTrbl, 'top', otherTrbl.top + LANE_MIN_HEIGHT);
|
||||
addMax(maxTrbl, 'top', otherTrbl.top + LANE_MIN_DIMENSIONS.height);
|
||||
}
|
||||
|
||||
// min top size (based on self or nested element)
|
||||
if (abs(laneTrbl.top - otherTrbl.top) < 5) {
|
||||
addMin(minTrbl, 'top', otherTrbl.bottom - LANE_MIN_HEIGHT);
|
||||
addMin(minTrbl, 'top', otherTrbl.bottom - LANE_MIN_DIMENSIONS.height);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,12 +89,12 @@ export function getParticipantResizeConstraints(laneShape, resizeDirection, bala
|
|||
|
||||
// max bottom size (based on previous element)
|
||||
if (balanced && abs(laneTrbl.bottom - otherTrbl.top) < 10) {
|
||||
addMin(maxTrbl, 'bottom', otherTrbl.bottom - LANE_MIN_HEIGHT);
|
||||
addMin(maxTrbl, 'bottom', otherTrbl.bottom - LANE_MIN_DIMENSIONS.height);
|
||||
}
|
||||
|
||||
// min bottom size (based on self or nested element)
|
||||
if (abs(laneTrbl.bottom - otherTrbl.bottom) < 5) {
|
||||
addMax(minTrbl, 'bottom', otherTrbl.top + LANE_MIN_HEIGHT);
|
||||
addMax(minTrbl, 'bottom', otherTrbl.top + LANE_MIN_DIMENSIONS.height);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -9,9 +9,9 @@ import { is } from '../../../util/ModelUtil';
|
|||
* Return true if element has any of the given types.
|
||||
*
|
||||
* @param {djs.model.Base} element
|
||||
* @param {Array<String>} types
|
||||
* @param {Array<string>} types
|
||||
*
|
||||
* @return {Boolean}
|
||||
* @return {boolean}
|
||||
*/
|
||||
export function isAny(element, types) {
|
||||
return some(types, function(t) {
|
||||
|
@ -24,7 +24,7 @@ export function isAny(element, types) {
|
|||
* Return the parent of the element with any of the given types.
|
||||
*
|
||||
* @param {djs.model.Base} element
|
||||
* @param {String|Array<String>} anyType
|
||||
* @param {string|Array<string>} anyType
|
||||
*
|
||||
* @return {djs.model.Base}
|
||||
*/
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
*
|
||||
* @param {djs.model.Base} element
|
||||
*
|
||||
* @return {Boolean}
|
||||
* @return {boolean}
|
||||
*/
|
||||
export function isDifferentType(element) {
|
||||
|
||||
|
|
|
@ -201,7 +201,7 @@ BpmnRules.prototype.canCopy = canCopy;
|
|||
* Checks if given element can be used for starting connection.
|
||||
*
|
||||
* @param {Element} source
|
||||
* @return {Boolean}
|
||||
* @return {boolean}
|
||||
*/
|
||||
function canStartConnection(element) {
|
||||
if (nonExistingOrLabel(element)) {
|
||||
|
@ -435,7 +435,7 @@ function canConnect(source, target, connection) {
|
|||
/**
|
||||
* Can an element be dropped into the target element
|
||||
*
|
||||
* @return {Boolean}
|
||||
* @return {boolean}
|
||||
*/
|
||||
function canDrop(element, target, position) {
|
||||
|
||||
|
|
|
@ -39,10 +39,10 @@ BpmnSearchProvider.$inject = [
|
|||
*
|
||||
* <Token> :
|
||||
* {
|
||||
* normal|matched: <String>
|
||||
* normal|matched: <string>
|
||||
* }
|
||||
*
|
||||
* @param {String} pattern
|
||||
* @param {string} pattern
|
||||
* @return {Array<Result>}
|
||||
*/
|
||||
BpmnSearchProvider.prototype.find = function(pattern) {
|
||||
|
|
|
@ -19,9 +19,9 @@ var diRefs = new Refs(
|
|||
* Returns true if an element has the given meta-model type
|
||||
*
|
||||
* @param {ModdleElement} element
|
||||
* @param {String} type
|
||||
* @param {string} type
|
||||
*
|
||||
* @return {Boolean}
|
||||
* @return {boolean}
|
||||
*/
|
||||
function is(element, type) {
|
||||
return element.$instanceOf(type);
|
||||
|
|
|
@ -17,7 +17,7 @@ export var FLOW_LABEL_INDENT = 15;
|
|||
* Returns true if the given semantic has an external label
|
||||
*
|
||||
* @param {BpmnElement} semantic
|
||||
* @return {Boolean} true if has label
|
||||
* @return {boolean} true if has label
|
||||
*/
|
||||
export function isLabelExternal(semantic) {
|
||||
return is(semantic, 'bpmn:Event') ||
|
||||
|
@ -35,7 +35,7 @@ export function isLabelExternal(semantic) {
|
|||
* Returns true if the given element has an external label
|
||||
*
|
||||
* @param {djs.model.shape} element
|
||||
* @return {Boolean} true if has label
|
||||
* @return {boolean} true if has label
|
||||
*/
|
||||
export function hasExternalLabel(element) {
|
||||
return isLabel(element.label);
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
* Is an element of the given BPMN type?
|
||||
*
|
||||
* @param {djs.model.Base|ModdleElement} element
|
||||
* @param {String} type
|
||||
* @param {string} type
|
||||
*
|
||||
* @return {Boolean}
|
||||
* @return {boolean}
|
||||
*/
|
||||
export function is(element, type) {
|
||||
var bo = getBusinessObject(element);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "bpmn-js",
|
||||
"version": "6.4.2",
|
||||
"version": "6.5.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -1103,7 +1103,8 @@
|
|||
"bpmn-font": {
|
||||
"version": "0.9.3",
|
||||
"resolved": "https://registry.npmjs.org/bpmn-font/-/bpmn-font-0.9.3.tgz",
|
||||
"integrity": "sha512-kzRGXGLzTROLRNCSskkOyj/+SbtTAn2unKfgB9tNt7RWJFybg/Wbe9YjK2ALotI3b64wwlCTkAalXiTiskP6dg=="
|
||||
"integrity": "sha512-kzRGXGLzTROLRNCSskkOyj/+SbtTAn2unKfgB9tNt7RWJFybg/Wbe9YjK2ALotI3b64wwlCTkAalXiTiskP6dg==",
|
||||
"dev": true
|
||||
},
|
||||
"bpmn-moddle": {
|
||||
"version": "6.0.6",
|
||||
|
@ -2026,9 +2027,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"diagram-js": {
|
||||
"version": "6.4.1",
|
||||
"resolved": "https://registry.npmjs.org/diagram-js/-/diagram-js-6.4.1.tgz",
|
||||
"integrity": "sha512-VqzydNl6RmnWuHT1B82VId7mH+TG+yZYkgEDp5BizaVDJyhl2F9Z1/q+X9FUQaBq08ZMW1NQP/Bljn56nGHjKw==",
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/diagram-js/-/diagram-js-6.6.1.tgz",
|
||||
"integrity": "sha512-3SlXwT2ieXCZkQn8dVZWfNry9+6d4R+0Q57Oz9t/SfIyNIrRPg0c9IlsaTHpGUhPE3fossXPDjmvqjJD0lmBLw==",
|
||||
"requires": {
|
||||
"css.escape": "^1.5.1",
|
||||
"didi": "^4.0.0",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "bpmn-js",
|
||||
"version": "6.4.2",
|
||||
"version": "6.5.0",
|
||||
"description": "A bpmn 2.0 toolkit and web modeler",
|
||||
"scripts": {
|
||||
"all": "run-s lint test distro test:distro",
|
||||
|
@ -39,6 +39,7 @@
|
|||
"*.css"
|
||||
],
|
||||
"devDependencies": {
|
||||
"bpmn-font": "^0.9.3",
|
||||
"camunda-bpmn-moddle": "^4.0.1",
|
||||
"chai": "^4.1.2",
|
||||
"chai-match": "^1.1.1",
|
||||
|
@ -79,10 +80,9 @@
|
|||
"webpack": "^4.35.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"bpmn-font": "^0.9.3",
|
||||
"bpmn-moddle": "^6.0.6",
|
||||
"css.escape": "^1.5.1",
|
||||
"diagram-js": "^6.4.1",
|
||||
"diagram-js": "^6.6.1",
|
||||
"diagram-js-direct-editing": "^1.6.1",
|
||||
"ids": "^1.0.0",
|
||||
"inherits": "^2.0.1",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="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" id="_tkxkICCPEeWwcL3w8i7dvw" targetNamespace="http://activiti.org/bpmn" exporter="camunda modeler" exporterVersion="2.7.0" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
|
||||
<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="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" id="_tkxkICCPEeWwcL3w8i7dvw" targetNamespace="http://activiti.org/bpmn" exporter="Camunda Modeler" exporterVersion="3.7.1" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
|
||||
<bpmn2:process id="Process_1" isExecutable="false">
|
||||
<bpmn2:subProcess id="SubProcess_1">
|
||||
<bpmn2:startEvent id="StartEvent_1">
|
||||
|
@ -15,43 +15,32 @@
|
|||
<bpmn2:boundaryEvent id="BoundaryEvent_2" name="superman" attachedToRef="Task_2" />
|
||||
<bpmn2:task id="CompensationTask" isForCompensation="true" />
|
||||
<bpmn2:intermediateThrowEvent id="IntermediateThrowEvent_1" name="joker" />
|
||||
<bpmn2:boundaryEvent id="BoundaryEvent_3" name="wonder woman" attachedToRef="SubProcess_1" />
|
||||
</bpmn2:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
|
||||
<bpmndi:BPMNShape id="_BPMNShape_SubProcess_2" bpmnElement="SubProcess_1" isExpanded="true">
|
||||
<dc:Bounds x="204" y="78" width="457" height="289" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_1" bpmnElement="SequenceFlow_1" sourceElement="_BPMNShape_StartEvent_2" targetElement="_BPMNShape_Task_2">
|
||||
<di:waypoint x="311" y="232" />
|
||||
<di:waypoint x="431" y="232" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="332" y="236" width="6" height="6" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
|
||||
<dc:Bounds x="275" y="214" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="293" y="255" width="0" height="0" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="_BPMNShape_SubProcess_2" bpmnElement="SubProcess_1" isExpanded="true">
|
||||
<dc:Bounds x="204" y="78" width="457" height="289" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="_BPMNShape_Task_2" bpmnElement="Task_1">
|
||||
<dc:Bounds x="431" y="192" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_1" bpmnElement="SequenceFlow_1" sourceElement="_BPMNShape_StartEvent_2" targetElement="_BPMNShape_Task_2">
|
||||
<di:waypoint xsi:type="dc:Point" x="311" y="232" />
|
||||
<di:waypoint xsi:type="dc:Point" x="431" y="232" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="332" y="236" width="6" height="6" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="BoundaryEvent_1_di" bpmnElement="BoundaryEvent_1">
|
||||
<dc:Bounds x="185" y="349" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="155" y="390" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Task_2_di" bpmnElement="Task_2">
|
||||
<dc:Bounds x="795" y="75" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="BoundaryEvent_2_di" bpmnElement="BoundaryEvent_2">
|
||||
<dc:Bounds x="781" y="140" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="754" y="176" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="CompensationTask_di" bpmnElement="CompensationTask">
|
||||
<dc:Bounds x="795" y="249" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
|
@ -61,6 +50,24 @@
|
|||
<dc:Bounds x="191" y="525" width="24" height="14" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="BoundaryEvent_2_di" bpmnElement="BoundaryEvent_2">
|
||||
<dc:Bounds x="781" y="140" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="754" y="176" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="BoundaryEvent_1_di" bpmnElement="BoundaryEvent_1">
|
||||
<dc:Bounds x="185" y="349" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="155" y="390" width="90" height="20" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_1kn7msk_di" bpmnElement="BoundaryEvent_3">
|
||||
<dc:Bounds x="412" y="349" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="393" y="392" width="75" height="14" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn2:definitions>
|
||||
|
|
|
@ -142,7 +142,7 @@ export function bootstrapBpmnJS(BpmnJS, diagram, options, locals) {
|
|||
*
|
||||
* });
|
||||
*
|
||||
* @param {String} xml document to display
|
||||
* @param {string} xml document to display
|
||||
* @param {Object} (options) optional options to be passed to the diagram upon instantiation
|
||||
* @param {Object|Function} locals the local overrides to be used by the diagram or a function that produces them
|
||||
* @return {Function} a function to be passed to beforeEach
|
||||
|
@ -170,7 +170,7 @@ export function bootstrapModeler(diagram, options, locals) {
|
|||
*
|
||||
* });
|
||||
*
|
||||
* @param {String} xml document to display
|
||||
* @param {string} xml document to display
|
||||
* @param {Object} (options) optional options to be passed to the diagram upon instantiation
|
||||
* @param {Object|Function} locals the local overrides to be used by the diagram or a function that produces them
|
||||
* @return {Function} a function to be passed to beforeEach
|
||||
|
|
|
@ -61,7 +61,7 @@ CustomElementFactory.$inject = [ 'injector' ];
|
|||
* return shapes[type];
|
||||
*
|
||||
*
|
||||
* @param {String} type
|
||||
* @param {string} type
|
||||
*
|
||||
* @return {Bounds} { width, height}
|
||||
*/
|
||||
|
|
|
@ -267,6 +267,21 @@ describe('Viewer', function() {
|
|||
});
|
||||
});
|
||||
|
||||
|
||||
it('should throw error due to missing diagram', function(done) {
|
||||
|
||||
var xml = require('../fixtures/bpmn/empty-definitions.bpmn');
|
||||
|
||||
// when
|
||||
createViewer(xml, function(err, warnings) {
|
||||
|
||||
// then
|
||||
expect(err.message).to.eql('no diagram to display');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
@ -549,25 +564,6 @@ describe('Viewer', function() {
|
|||
|
||||
});
|
||||
|
||||
|
||||
it('should throw error due to missing diagram', function(done) {
|
||||
|
||||
var xml = require('../fixtures/bpmn/empty-definitions.bpmn');
|
||||
|
||||
// given
|
||||
viewer = new Viewer({ container: container, additionalModules: testModules });
|
||||
|
||||
// when
|
||||
viewer.importXML(xml, function(err) {
|
||||
|
||||
// then
|
||||
expect(err.message).to.eql('no diagram to display');
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -416,8 +416,8 @@ describe('draw - bpmn renderer', function() {
|
|||
*
|
||||
* @param {djs.model.base} element - Element.
|
||||
* @param {SVG} gfx - Graphics of element.
|
||||
* @param {String} fillColor - Fill color to expect.
|
||||
* @param {String} strokeColor - Stroke color to expect.
|
||||
* @param {string} fillColor - Fill color to expect.
|
||||
* @param {string} strokeColor - Stroke color to expect.
|
||||
*/
|
||||
function expectColors(element, gfx, fillColor, strokeColor) {
|
||||
var djsVisual = domQuery('.djs-visual', gfx);
|
||||
|
|
|
@ -11,14 +11,12 @@ import selectionModule from 'diagram-js/lib/features/selection';
|
|||
|
||||
import { getBusinessObject } from '../../../../lib/util/ModelUtil';
|
||||
|
||||
import { getMid } from 'diagram-js/lib/layout/LayoutUtil';
|
||||
|
||||
|
||||
describe('features/auto-place', function() {
|
||||
|
||||
describe('element placement', function() {
|
||||
|
||||
var diagramXML = require('./AutoPlace.bpmn');
|
||||
var diagramXML = require('./BpmnAutoPlace.bpmn');
|
||||
|
||||
before(bootstrapModeler(diagramXML, {
|
||||
modules: [
|
||||
|
@ -116,7 +114,7 @@ describe('features/auto-place', function() {
|
|||
|
||||
describe('integration', function() {
|
||||
|
||||
var diagramXML = require('./AutoPlace.bpmn');
|
||||
var diagramXML = require('./BpmnAutoPlace.bpmn');
|
||||
|
||||
before(bootstrapModeler(diagramXML, {
|
||||
modules: [
|
||||
|
@ -174,7 +172,7 @@ describe('features/auto-place', function() {
|
|||
|
||||
describe('multi connection handling', function() {
|
||||
|
||||
var diagramXML = require('./AutoPlace.multi-connection.bpmn');
|
||||
var diagramXML = require('./BpmnAutoPlace.multi-connection.bpmn');
|
||||
|
||||
before(bootstrapModeler(diagramXML, {
|
||||
modules: [
|
||||
|
@ -209,7 +207,7 @@ describe('features/auto-place', function() {
|
|||
|
||||
describe('boundary event connection handling', function() {
|
||||
|
||||
var diagramXML = require('./AutoPlace.boundary-events.bpmn');
|
||||
var diagramXML = require('./BpmnAutoPlace.boundary-events.bpmn');
|
||||
|
||||
before(bootstrapModeler(diagramXML, {
|
||||
modules: [
|
||||
|
@ -241,12 +239,14 @@ describe('features/auto-place', function() {
|
|||
expectedBounds: { x: 242, y: -27, width: 100, height: 80 }
|
||||
}));
|
||||
|
||||
|
||||
it('should place top right of BOUNDARY_TOP_RIGHT without infinite loop', autoPlace({
|
||||
element: 'bpmn:Task',
|
||||
behind: 'BOUNDARY_TOP_RIGHT',
|
||||
expectedBounds: { x: 473, y: -27, width: 100, height: 80 }
|
||||
}));
|
||||
|
||||
|
||||
it('should place top right of BOUNDARY_SUBPROCESS_TOP', autoPlace({
|
||||
element: 'bpmn:Task',
|
||||
behind: 'BOUNDARY_SUBPROCESS_TOP',
|
||||
|
@ -255,114 +255,10 @@ describe('features/auto-place', function() {
|
|||
|
||||
});
|
||||
|
||||
|
||||
describe('eventbus integration', function() {
|
||||
|
||||
var diagramXML = require('./AutoPlace.bpmn');
|
||||
|
||||
beforeEach(bootstrapModeler(diagramXML, {
|
||||
modules: [
|
||||
autoPlaceModule,
|
||||
coreModule,
|
||||
labelEditingModule,
|
||||
modelingModule,
|
||||
selectionModule
|
||||
]
|
||||
}));
|
||||
|
||||
|
||||
it('<autoPlace.start>', inject(
|
||||
function(autoPlace, elementFactory, elementRegistry, eventBus) {
|
||||
|
||||
// given
|
||||
var element = elementFactory.createShape({ type: 'bpmn:Task' });
|
||||
|
||||
var source = elementRegistry.get('TASK_2');
|
||||
|
||||
var listener = sinon.spy(function(event) {
|
||||
|
||||
// then
|
||||
expect(event.shape).to.equal(element);
|
||||
expect(event.source).to.equal(source);
|
||||
});
|
||||
|
||||
eventBus.on('autoPlace.start', listener);
|
||||
|
||||
// when
|
||||
autoPlace.append(source, element);
|
||||
|
||||
expect(listener).to.have.been.called;
|
||||
}
|
||||
));
|
||||
|
||||
|
||||
it('<autoPlace>', inject(
|
||||
function(autoPlace, elementFactory, elementRegistry, eventBus) {
|
||||
|
||||
// given
|
||||
var element = elementFactory.createShape({ type: 'bpmn:Task' });
|
||||
|
||||
var source = elementRegistry.get('TASK_2');
|
||||
|
||||
var listener = sinon.spy(function(event) {
|
||||
|
||||
// then
|
||||
expect(event.shape).to.equal(element);
|
||||
expect(event.source).to.equal(source);
|
||||
|
||||
return {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
});
|
||||
|
||||
eventBus.on('autoPlace', listener);
|
||||
|
||||
// when
|
||||
autoPlace.append(source, element);
|
||||
|
||||
expect(listener).to.have.been.called;
|
||||
|
||||
expect(getMid(element)).to.eql({
|
||||
x: 0,
|
||||
y: 0
|
||||
});
|
||||
}
|
||||
));
|
||||
|
||||
|
||||
it('<autoPlace.end>', inject(
|
||||
function(autoPlace, elementFactory, elementRegistry, eventBus) {
|
||||
|
||||
// given
|
||||
var element = elementFactory.createShape({ type: 'bpmn:Task' });
|
||||
|
||||
var source = elementRegistry.get('TASK_2');
|
||||
|
||||
var listener = sinon.spy(function(event) {
|
||||
|
||||
// then
|
||||
expect(event.shape).to.equal(element);
|
||||
expect(event.source).to.equal(source);
|
||||
});
|
||||
|
||||
eventBus.on('autoPlace.end', listener);
|
||||
|
||||
// when
|
||||
autoPlace.append(source, element);
|
||||
|
||||
expect(listener).to.have.been.called;
|
||||
}
|
||||
));
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
// helpers //////////////////////
|
||||
// helpers //////////
|
||||
|
||||
function autoPlace(cfg) {
|
||||
|
|
@ -834,7 +834,7 @@ describe('features/copy-paste', function() {
|
|||
/**
|
||||
* Integration test involving copying, pasting, moving, undoing and redoing.
|
||||
*
|
||||
* @param {String|Array<String>} elementIds
|
||||
* @param {string|Array<string>} elementIds
|
||||
*/
|
||||
function integrationTest(elementIds) {
|
||||
if (!isArray(elementIds)) {
|
||||
|
@ -1000,7 +1000,7 @@ function _findDescriptorsInTree(elements, tree, depth) {
|
|||
/**
|
||||
* Copy elements.
|
||||
*
|
||||
* @param {Array<String|djs.model.Base} elements
|
||||
* @param {Array<string|djs.model.Base} elements
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
|
|
@ -3,6 +3,8 @@ import {
|
|||
inject
|
||||
} from 'test/TestHelper';
|
||||
|
||||
import { pick } from 'min-dash';
|
||||
|
||||
import {
|
||||
getBusinessObject
|
||||
} from 'lib/util/ModelUtil';
|
||||
|
@ -123,4 +125,35 @@ describe('features/modeling - resize shape', function() {
|
|||
|
||||
});
|
||||
|
||||
|
||||
describe('integration', function() {
|
||||
|
||||
var diagramXML = require('../../../fixtures/bpmn/boundary-events.bpmn');
|
||||
|
||||
var testModules = [ coreModule, modelingModule ];
|
||||
|
||||
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
|
||||
|
||||
|
||||
it('should not move Boundary Event if unnecessary', inject(function(elementRegistry, modeling) {
|
||||
|
||||
// given
|
||||
var boundaryEvent = elementRegistry.get('BoundaryEvent_3'),
|
||||
originalPosition = getPosition(boundaryEvent),
|
||||
subProcessElement = elementRegistry.get('SubProcess_1');
|
||||
|
||||
// when
|
||||
modeling.resizeShape(subProcessElement, { x: 204, y: 28, width: 400, height: 339 });
|
||||
|
||||
// then
|
||||
expect(getPosition(boundaryEvent)).to.jsonEqual(originalPosition);
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// helper /////
|
||||
function getPosition(shape) {
|
||||
return pick(shape, [ 'x', 'y' ]);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,11 @@ import {
|
|||
createCanvasEvent as canvasEvent
|
||||
} from '../../../../util/MockEvents';
|
||||
|
||||
import { SUB_PROCESS_MIN_DIMENSIONS } from 'lib/features/modeling/behavior/ResizeBehavior';
|
||||
import {
|
||||
LANE_MIN_DIMENSIONS,
|
||||
PARTICIPANT_MIN_DIMENSIONS,
|
||||
SUB_PROCESS_MIN_DIMENSIONS
|
||||
} from 'lib/features/modeling/behavior/ResizeBehavior';
|
||||
|
||||
var testModules = [
|
||||
coreModule,
|
||||
|
@ -26,16 +30,16 @@ var testModules = [
|
|||
|
||||
describe('features/modeling - space tool behavior', function() {
|
||||
|
||||
describe('participant', function() {
|
||||
describe('subprocess', function() {
|
||||
|
||||
describe('minimum dimensions', function() {
|
||||
|
||||
var diagramXML = require('./SpaceToolBehaviorSpec.bpmn');
|
||||
var diagramXML = require('./SpaceToolBehaviorSpec.subprocess.bpmn');
|
||||
|
||||
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
|
||||
|
||||
|
||||
it('should ensure minimum dimensions', inject(
|
||||
it('should ensure subprocess minimum dimensions', inject(
|
||||
function(dragging, elementRegistry, spaceTool) {
|
||||
|
||||
// given
|
||||
|
@ -57,4 +61,92 @@ describe('features/modeling - space tool behavior', function() {
|
|||
|
||||
});
|
||||
|
||||
describe('participant', function() {
|
||||
|
||||
describe('minimum dimensions', function() {
|
||||
|
||||
var diagramXML = require('./SpaceToolBehaviorSpec.participant.bpmn');
|
||||
|
||||
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
|
||||
|
||||
|
||||
it('should ensure participant minimum width', inject(
|
||||
function(dragging, elementRegistry, spaceTool) {
|
||||
|
||||
// given
|
||||
var participant = elementRegistry.get('Participant_1');
|
||||
|
||||
// when
|
||||
spaceTool.activateMakeSpace(canvasEvent({ x: 300, y: 0 }));
|
||||
|
||||
dragging.move(canvasEvent({ x: -200, y: 0 }));
|
||||
|
||||
dragging.end();
|
||||
|
||||
// then
|
||||
expect(participant.width).to.equal(PARTICIPANT_MIN_DIMENSIONS.width);
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
it('should ensure participant minimum height', inject(
|
||||
function(dragging, elementRegistry, spaceTool) {
|
||||
|
||||
// given
|
||||
var participant = elementRegistry.get('Participant_1');
|
||||
|
||||
// when
|
||||
spaceTool.activateMakeSpace(canvasEvent({ x: 0, y: 100 }));
|
||||
|
||||
dragging.move(canvasEvent({ x: 0, y: -400 }));
|
||||
|
||||
dragging.end();
|
||||
|
||||
// then
|
||||
expect(participant.height).to.equal(PARTICIPANT_MIN_DIMENSIONS.height);
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
it('should ensure lane minimum height', inject(
|
||||
function(dragging, elementRegistry, spaceTool) {
|
||||
|
||||
// given
|
||||
var lane = elementRegistry.get('Lane_1');
|
||||
|
||||
// when
|
||||
spaceTool.activateMakeSpace(canvasEvent({ x: 0, y: 400 }));
|
||||
|
||||
dragging.move(canvasEvent({ x: 0, y: 0 }));
|
||||
|
||||
dragging.end();
|
||||
|
||||
// then
|
||||
expect(lane.height).to.equal(LANE_MIN_DIMENSIONS.height);
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
it('should ensure nested lane minimum height', inject(
|
||||
function(dragging, elementRegistry, spaceTool) {
|
||||
|
||||
// given
|
||||
var lane = elementRegistry.get('Lane_6');
|
||||
|
||||
// when
|
||||
spaceTool.activateMakeSpace(canvasEvent({ x: 0, y: 925 }));
|
||||
|
||||
dragging.move(canvasEvent({ x: 0, y: 0 }));
|
||||
|
||||
dragging.end();
|
||||
|
||||
// then
|
||||
expect(lane.height).to.equal(LANE_MIN_DIMENSIONS.height);
|
||||
})
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
|
@ -0,0 +1,57 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bpmn:definitions 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" id="Definitions_0mdr1un" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.7.0">
|
||||
<bpmn:collaboration id="Collaboration_1">
|
||||
<bpmn:participant id="Participant_1" name="Participant_1" processRef="Process_1" />
|
||||
<bpmn:participant id="Participant_2" name="Participant_2" processRef="Process_2" />
|
||||
<bpmn:participant id="Participant_3" name="Participant_3" processRef="Process_3" />
|
||||
</bpmn:collaboration>
|
||||
<bpmn:process id="Process_1" isExecutable="true" />
|
||||
<bpmn:process id="Process_2" isExecutable="false">
|
||||
<bpmn:laneSet id="LaneSet_16fkurg">
|
||||
<bpmn:lane id="Lane_1" name="Lane_1" />
|
||||
<bpmn:lane id="Lane_2" name="Lane_2" />
|
||||
</bpmn:laneSet>
|
||||
</bpmn:process>
|
||||
<bpmn:process id="Process_3" isExecutable="false">
|
||||
<bpmn:laneSet id="LaneSet_04c016w">
|
||||
<bpmn:lane id="Lane_3" name="Lane_3" />
|
||||
<bpmn:lane id="Lane_4" name="Lane_4">
|
||||
<bpmn:childLaneSet id="LaneSet_1eow6b9">
|
||||
<bpmn:lane id="Lane_5" name="Lane_5" />
|
||||
<bpmn:lane id="Lane_6" name="Lane_6" />
|
||||
</bpmn:childLaneSet>
|
||||
</bpmn:lane>
|
||||
</bpmn:laneSet>
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_1">
|
||||
<bpmndi:BPMNShape id="Participant_06757og_di" bpmnElement="Participant_1" isHorizontal="true">
|
||||
<dc:Bounds x="0" y="0" width="600" height="250" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Participant_0ae1cne_di" bpmnElement="Participant_2" isHorizontal="true">
|
||||
<dc:Bounds x="700" y="350" width="600" height="250" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Lane_030yoo3_di" bpmnElement="Lane_1" isHorizontal="true">
|
||||
<dc:Bounds x="730" y="350" width="570" height="130" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Lane_1bwlv2s_di" bpmnElement="Lane_2" isHorizontal="true">
|
||||
<dc:Bounds x="730" y="480" width="570" height="120" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Participant_01wmlzw_di" bpmnElement="Participant_3" isHorizontal="true">
|
||||
<dc:Bounds x="1400" y="700" width="600" height="250" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Lane_0jco8kr_di" bpmnElement="Lane_3" isHorizontal="true">
|
||||
<dc:Bounds x="1430" y="700" width="570" height="125" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Lane_0zojmuw_di" bpmnElement="Lane_4" isHorizontal="true">
|
||||
<dc:Bounds x="1430" y="825" width="570" height="125" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Lane_1xlpjnj_di" bpmnElement="Lane_5" isHorizontal="true">
|
||||
<dc:Bounds x="1460" y="825" width="540" height="63" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Lane_0k03ea4_di" bpmnElement="Lane_6" isHorizontal="true">
|
||||
<dc:Bounds x="1460" y="888" width="540" height="62" />
|
||||
</bpmndi:BPMNShape>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
|
@ -5,6 +5,7 @@ import {
|
|||
} from 'test/TestHelper';
|
||||
|
||||
import {
|
||||
map,
|
||||
pick
|
||||
} from 'min-dash';
|
||||
|
||||
|
@ -270,6 +271,45 @@ describe('features/modeling - add Lane', function() {
|
|||
});
|
||||
|
||||
|
||||
describe('flow node handling', function() {
|
||||
|
||||
var diagramXML = require('./lanes.bpmn');
|
||||
|
||||
beforeEach(bootstrapModeler(diagramXML, {
|
||||
modules: testModules
|
||||
}));
|
||||
|
||||
|
||||
it('should move flow nodes and sequence flows', inject(function(elementRegistry, modeling) {
|
||||
|
||||
// given
|
||||
var laneShape = elementRegistry.get('Nested_Lane_B'),
|
||||
task_Boundary = elementRegistry.get('Task_Boundary'),
|
||||
boundary = elementRegistry.get('Boundary'),
|
||||
sequenceFlow = elementRegistry.get('SequenceFlow'),
|
||||
sequenceFlow_From_Boundary = elementRegistry.get('SequenceFlow_From_Boundary');
|
||||
|
||||
// when
|
||||
var newLane = modeling.addLane(laneShape, 'top');
|
||||
|
||||
// then
|
||||
expect(task_Boundary).to.have.position({ x: 264, y: -57 });
|
||||
expect(boundary).to.have.position({ x: 311, y: 5 });
|
||||
|
||||
expect(sequenceFlow_From_Boundary).to.have.waypoints([
|
||||
{ x: 329, y: 161 - newLane.height },
|
||||
{ x: 329, y: 188 - newLane.height },
|
||||
{ x: 482, y: 188 - newLane.height },
|
||||
{ x: 482, y: 143 - newLane.height }
|
||||
]);
|
||||
|
||||
expect(sequenceFlow).to.have.waypoints([
|
||||
{ x: 364, y: 103 - newLane.height },
|
||||
{ x: 432, y: 103 - newLane.height }
|
||||
]);
|
||||
}));
|
||||
});
|
||||
|
||||
describe('flow node handling', function() {
|
||||
|
||||
var diagramXML = require('./lanes-flow-nodes.bpmn');
|
||||
|
@ -278,6 +318,7 @@ describe('features/modeling - add Lane', function() {
|
|||
modules: testModules
|
||||
}));
|
||||
|
||||
|
||||
function addLaneAbove(laneId) {
|
||||
|
||||
return getBpmnJS().invoke(function(elementRegistry, modeling) {
|
||||
|
@ -289,19 +330,32 @@ describe('features/modeling - add Lane', function() {
|
|||
});
|
||||
}
|
||||
|
||||
function addLaneBelow(laneId) {
|
||||
|
||||
return getBpmnJS().invoke(function(elementRegistry, modeling) {
|
||||
var existingLane = elementRegistry.get(laneId);
|
||||
|
||||
expect(existingLane).to.exist;
|
||||
|
||||
return modeling.addLane(existingLane, 'bottom');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
it('should move flow nodes', inject(function(elementRegistry, modeling) {
|
||||
|
||||
// given
|
||||
var task_Boundary = elementRegistry.get('Task_Boundary'),
|
||||
boundary = elementRegistry.get('Boundary');
|
||||
taskPosition = getPosition(task_Boundary),
|
||||
boundary = elementRegistry.get('Boundary'),
|
||||
boundaryPosition = getPosition(boundary);
|
||||
|
||||
// when
|
||||
addLaneAbove('Nested_Lane_B');
|
||||
|
||||
// then
|
||||
expect(task_Boundary).to.have.position({ x: 344, y: -7 });
|
||||
expect(boundary).to.have.position({ x: 391, y: 55 });
|
||||
expect(task_Boundary).to.have.position({ x: taskPosition.x, y: taskPosition.y - 120 });
|
||||
expect(boundary).to.have.position({ x: boundaryPosition.x, y: boundaryPosition.y - 120 });
|
||||
}));
|
||||
|
||||
|
||||
|
@ -309,22 +363,54 @@ describe('features/modeling - add Lane', function() {
|
|||
|
||||
// given
|
||||
var sequenceFlow = elementRegistry.get('SequenceFlow'),
|
||||
sequenceFlow_From_Boundary = elementRegistry.get('SequenceFlow_From_Boundary');
|
||||
sequenceFlowWaypoints = sequenceFlow.waypoints,
|
||||
sequenceFlow_From_Boundary = elementRegistry.get('SequenceFlow_From_Boundary'),
|
||||
sequenceFlow_From_BoundaryWaypoints = sequenceFlow_From_Boundary.waypoints;
|
||||
|
||||
// when
|
||||
addLaneAbove('Nested_Lane_B');
|
||||
|
||||
// then
|
||||
expect(sequenceFlow_From_Boundary).to.have.waypoints([
|
||||
{ x: 409, y: 91 },
|
||||
{ x: 409, y: 118 },
|
||||
{ x: 562, y: 118 },
|
||||
{ x: 562, y: 73 }
|
||||
]);
|
||||
expect(sequenceFlow_From_Boundary).to.have.waypoints(
|
||||
moveWaypoints(sequenceFlow_From_BoundaryWaypoints, 0, -120)
|
||||
);
|
||||
|
||||
expect(sequenceFlow).to.have.waypoints([
|
||||
{ x: 444, y: 33 },
|
||||
{ x: 512, y: 33 }
|
||||
expect(sequenceFlow).to.have.waypoints(
|
||||
moveWaypoints(sequenceFlowWaypoints, 0, -120)
|
||||
);
|
||||
}));
|
||||
|
||||
|
||||
it('should move message flows when lane added above', inject(function(elementRegistry) {
|
||||
|
||||
// given
|
||||
var messageFlow = elementRegistry.get('MessageFlowAbove'),
|
||||
messageFlowWaypoints = messageFlow.waypoints;
|
||||
|
||||
// when
|
||||
addLaneAbove('Nested_Lane_B');
|
||||
|
||||
// then
|
||||
expect(messageFlow).to.have.waypoints([
|
||||
movePosition(messageFlowWaypoints[0], 0, -120),
|
||||
messageFlowWaypoints[1]
|
||||
]);
|
||||
}));
|
||||
|
||||
|
||||
it('should move message flows when lane added below', inject(function(elementRegistry) {
|
||||
|
||||
// given
|
||||
var messageFlow = elementRegistry.get('MessageFlowBelow'),
|
||||
messageFlowWaypoints = messageFlow.waypoints;
|
||||
|
||||
// when
|
||||
addLaneBelow('Nested_Lane_B');
|
||||
|
||||
// then
|
||||
expect(messageFlow).to.have.waypoints([
|
||||
messageFlowWaypoints[0],
|
||||
movePosition(messageFlowWaypoints[1], 0, 120)
|
||||
]);
|
||||
}));
|
||||
|
||||
|
@ -333,7 +419,8 @@ describe('features/modeling - add Lane', function() {
|
|||
|
||||
// given
|
||||
var event = elementRegistry.get('Event'),
|
||||
label = event.label;
|
||||
label = event.label,
|
||||
labelPosition = getPosition(label);
|
||||
|
||||
// TODO(nikku): consolidate import + editing behavior => not consistent right now
|
||||
|
||||
|
@ -344,7 +431,10 @@ describe('features/modeling - add Lane', function() {
|
|||
addLaneAbove('Nested_Lane_B');
|
||||
|
||||
// then
|
||||
expect(label.y).to.eql(58);
|
||||
expect(label).to.have.position({
|
||||
x: labelPosition.x,
|
||||
y: labelPosition.y - 120
|
||||
});
|
||||
}));
|
||||
|
||||
});
|
||||
|
@ -408,3 +498,23 @@ function padEvent(entry) {
|
|||
};
|
||||
});
|
||||
}
|
||||
|
||||
function getPosition(element) {
|
||||
return {
|
||||
x: element.x,
|
||||
y: element.y
|
||||
};
|
||||
}
|
||||
|
||||
function moveWaypoints(waypoints, deltaX, deltaY) {
|
||||
return map(waypoints, function(waypoint) {
|
||||
return movePosition(waypoint, deltaX, deltaY);
|
||||
});
|
||||
}
|
||||
|
||||
function movePosition(point, deltaX, deltaY) {
|
||||
return {
|
||||
x: point.x + deltaX,
|
||||
y: point.y + deltaY
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="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" id="_4bAZoD9WEeWLcNBL4nCk1A" targetNamespace="http://camunda.org/schema/1.0/bpmn" exporter="bpmn-js (https://demo.bpmn.io)" exporterVersion="6.3.1" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
|
||||
<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="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" id="_4bAZoD9WEeWLcNBL4nCk1A" targetNamespace="http://camunda.org/schema/1.0/bpmn" exporter="Camunda Modeler" exporterVersion="3.7.1" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
|
||||
<bpmn2:collaboration id="_Collaboration_2">
|
||||
<bpmn2:participant id="Participant_Lane" name="Participant_Lane" processRef="Process_Lane" />
|
||||
<bpmn2:participant id="ParticipantBelow" name="ParticipantBelow" processRef="Process_0kzdcfx" />
|
||||
<bpmn2:participant id="ParticipantAbove" name="ParticipantAbove" processRef="Process_1nej7ck" />
|
||||
<bpmn2:messageFlow id="MessageFlowBelow" sourceRef="ParticipantBelow" targetRef="Participant_Lane" />
|
||||
<bpmn2:messageFlow id="MessageFlowAbove" name="MessageFlowAbove" sourceRef="Participant_Lane" targetRef="ParticipantAbove" />
|
||||
</bpmn2:collaboration>
|
||||
<bpmn2:process id="Process_Lane" isExecutable="false">
|
||||
<bpmn2:laneSet id="LaneSet_1" name="Lane Set 1">
|
||||
|
@ -11,13 +15,13 @@
|
|||
<bpmn2:flowNodeRef>Event</bpmn2:flowNodeRef>
|
||||
<bpmn2:flowNodeRef>Boundary</bpmn2:flowNodeRef>
|
||||
<bpmn2:childLaneSet id="LaneSet_2">
|
||||
<bpmn2:lane id="Nested_Lane_B" name="Nested_Lane_B" />
|
||||
<bpmn2:lane id="Nested_Lane_A" name="Nested_Lane_A">
|
||||
<bpmn2:flowNodeRef>Task_Boundary</bpmn2:flowNodeRef>
|
||||
<bpmn2:flowNodeRef>Task</bpmn2:flowNodeRef>
|
||||
<bpmn2:flowNodeRef>Event</bpmn2:flowNodeRef>
|
||||
<bpmn2:flowNodeRef>Boundary</bpmn2:flowNodeRef>
|
||||
</bpmn2:lane>
|
||||
<bpmn2:lane id="Nested_Lane_B" name="Nested_Lane_B" />
|
||||
</bpmn2:childLaneSet>
|
||||
</bpmn2:lane>
|
||||
</bpmn2:laneSet>
|
||||
|
@ -32,57 +36,76 @@
|
|||
<bpmn2:boundaryEvent id="Boundary" name="Boundary" attachedToRef="Task_Boundary">
|
||||
<bpmn2:outgoing>SequenceFlow_From_Boundary</bpmn2:outgoing>
|
||||
</bpmn2:boundaryEvent>
|
||||
<bpmn2:sequenceFlow id="SequenceFlow" name="Flow" sourceRef="Task_Boundary" targetRef="Task" />
|
||||
<bpmn2:sequenceFlow id="SequenceFlow_From_Boundary" name="" sourceRef="Boundary" targetRef="Task" />
|
||||
<bpmn2:sequenceFlow id="SequenceFlow" name="Flow" sourceRef="Task_Boundary" targetRef="Task" />
|
||||
</bpmn2:process>
|
||||
<bpmn2:process id="Process_0kzdcfx" isExecutable="false" />
|
||||
<bpmn2:process id="Process_1nej7ck" isExecutable="false" />
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="_Collaboration_2">
|
||||
<bpmndi:BPMNShape id="_BPMNShape_Participant_2" bpmnElement="Participant_Lane" isHorizontal="true">
|
||||
<dc:Bounds x="152" y="83" width="540" height="537" />
|
||||
<dc:Bounds x="152" y="633" width="540" height="537" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="_BPMNShape_Task_2" bpmnElement="Task_Boundary">
|
||||
<dc:Bounds x="344" y="113" width="100" height="80" />
|
||||
<bpmndi:BPMNShape id="_BPMNShape_Lane_3" bpmnElement="Lane_A" isHorizontal="true">
|
||||
<dc:Bounds x="182" y="633" width="510" height="537" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="_BPMNShape_BoundaryEvent_2" bpmnElement="Boundary">
|
||||
<dc:Bounds x="391" y="175" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="339" y="210" width="48" height="14" />
|
||||
</bpmndi:BPMNLabel>
|
||||
<bpmndi:BPMNShape id="_BPMNShape_Lane_4" bpmnElement="Nested_Lane_A" isHorizontal="true">
|
||||
<dc:Bounds x="212" y="633" width="480" height="180" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="_BPMNShape_Task_3" bpmnElement="Task">
|
||||
<dc:Bounds x="512" y="113" width="100" height="80" />
|
||||
<bpmndi:BPMNShape id="_BPMNShape_Lane_5" bpmnElement="Nested_Lane_B" isHorizontal="true">
|
||||
<dc:Bounds x="212" y="813" width="480" height="357" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_1" bpmnElement="SequenceFlow_From_Boundary" sourceElement="_BPMNShape_BoundaryEvent_2" targetElement="_BPMNShape_Task_3">
|
||||
<di:waypoint x="409" y="211" />
|
||||
<di:waypoint x="409" y="238" />
|
||||
<di:waypoint x="562" y="238" />
|
||||
<di:waypoint x="562" y="193" />
|
||||
<di:waypoint x="409" y="761" />
|
||||
<di:waypoint x="409" y="788" />
|
||||
<di:waypoint x="562" y="788" />
|
||||
<di:waypoint x="562" y="743" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="377" y="188" width="6" height="6" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_2" bpmnElement="SequenceFlow" sourceElement="_BPMNShape_Task_2" targetElement="_BPMNShape_Task_3">
|
||||
<di:waypoint x="444" y="153" />
|
||||
<di:waypoint x="512" y="153" />
|
||||
<di:waypoint x="444" y="703" />
|
||||
<di:waypoint x="512" y="703" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="466" y="135" width="25" height="14" />
|
||||
<dc:Bounds x="467" y="685" width="24" height="14" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="_BPMNShape_Lane_3" bpmnElement="Lane_A" isHorizontal="true">
|
||||
<dc:Bounds x="182" y="83" width="510" height="537" />
|
||||
<bpmndi:BPMNShape id="_BPMNShape_Task_2" bpmnElement="Task_Boundary">
|
||||
<dc:Bounds x="344" y="663" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="_BPMNShape_Lane_4" bpmnElement="Nested_Lane_A" isHorizontal="true">
|
||||
<dc:Bounds x="212" y="83" width="480" height="180" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="_BPMNShape_Lane_5" bpmnElement="Nested_Lane_B" isHorizontal="true">
|
||||
<dc:Bounds x="212" y="263" width="480" height="357" />
|
||||
<bpmndi:BPMNShape id="_BPMNShape_Task_3" bpmnElement="Task">
|
||||
<dc:Bounds x="512" y="663" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_di" bpmnElement="Event">
|
||||
<dc:Bounds x="262" y="135" width="36" height="36" />
|
||||
<dc:Bounds x="262" y="685" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="268" y="178" width="24" height="14" />
|
||||
<dc:Bounds x="268" y="728" width="24" height="14" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="_BPMNShape_BoundaryEvent_2" bpmnElement="Boundary">
|
||||
<dc:Bounds x="391" y="725" width="36" height="36" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="339" y="760" width="48" height="14" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Participant_1nh1wgv_di" bpmnElement="ParticipantBelow" isHorizontal="true">
|
||||
<dc:Bounds x="152" y="1500" width="600" height="250" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Participant_05yp9aj_di" bpmnElement="ParticipantAbove" isHorizontal="true">
|
||||
<dc:Bounds x="152" y="80" width="600" height="250" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="Flow_1g3bwbi_di" bpmnElement="MessageFlowBelow">
|
||||
<di:waypoint x="452" y="1500" />
|
||||
<di:waypoint x="452" y="1170" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0n2j5uv_di" bpmnElement="MessageFlowAbove">
|
||||
<di:waypoint x="422" y="633" />
|
||||
<di:waypoint x="422" y="330" />
|
||||
<bpmndi:BPMNLabel>
|
||||
<dc:Bounds x="393" y="479" width="88" height="27" />
|
||||
</bpmndi:BPMNLabel>
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn2:definitions>
|
||||
|
|
|
@ -552,4 +552,119 @@ describe('features/modeling - layout', function() {
|
|||
|
||||
});
|
||||
|
||||
|
||||
describe('subProcess', function() {
|
||||
|
||||
var diagramXML = require('./LayoutSequenceFlowSpec.subProcess.bpmn');
|
||||
|
||||
var testModules = [ coreModule, modelingModule ];
|
||||
|
||||
beforeEach(bootstrapModeler(diagramXML, { modules: testModules }));
|
||||
|
||||
|
||||
it('should layout straight between subProcesses (top -> bottom)', function() {
|
||||
|
||||
// when
|
||||
var connection = connect('SubProcess_Center', 'SubProcess_Bottom'),
|
||||
source = connection.source,
|
||||
target = connection.target;
|
||||
|
||||
var expectedX = getMid(target).x;
|
||||
|
||||
// then
|
||||
expect(connection).to.have.waypoints([
|
||||
{ x: expectedX, y: source.y + source.height },
|
||||
{ x: expectedX, y: target.y }
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
it('should layout straight between subProcesses (bottom -> top)', function() {
|
||||
|
||||
// when
|
||||
var connection = connect('SubProcess_Bottom', 'SubProcess_Center'),
|
||||
source = connection.source,
|
||||
target = connection.target;
|
||||
|
||||
var expectedX = getMid(target).x;
|
||||
|
||||
// then
|
||||
expect(connection).to.have.waypoints([
|
||||
{ x: expectedX, y: source.y },
|
||||
{ x: expectedX, y: target.y + target.height }
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
it('should layout straight between subProcess and task next to it (subProcess -> task)',
|
||||
function() {
|
||||
|
||||
// when
|
||||
var connection = connect('SubProcess_Center', 'Task_Right'),
|
||||
source = connection.source,
|
||||
target = connection.target;
|
||||
|
||||
var expectedY = getMid(target).y;
|
||||
|
||||
// then
|
||||
expect(connection).to.have.waypoints([
|
||||
{ x: source.x + source.width, y: expectedY },
|
||||
{ x: target.x, y: expectedY }
|
||||
]);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
it('should layout straight between subProcess and task next to it (task -> subProcess)',
|
||||
function() {
|
||||
|
||||
// when
|
||||
var connection = connect('Task_Right', 'SubProcess_Center'),
|
||||
source = connection.source,
|
||||
target = connection.target;
|
||||
|
||||
var expectedY = getMid(source).y;
|
||||
|
||||
// then
|
||||
expect(connection).to.have.waypoints([
|
||||
{ x: source.x, y: expectedY },
|
||||
{ x: target.x + target.width, y: expectedY }
|
||||
]);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
it('should layout straight between subProcess and task above (subProcess -> task)', function() {
|
||||
|
||||
// when
|
||||
var connection = connect('SubProcess_Center', 'Task_Top'),
|
||||
source = connection.source,
|
||||
target = connection.target;
|
||||
|
||||
var expectedX = getMid(target).x;
|
||||
|
||||
// then
|
||||
expect(connection).to.have.waypoints([
|
||||
{ x: expectedX, y: source.y },
|
||||
{ x: expectedX, y: target.y + target.height }
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
it('should layout straight between subProcess and task above (task -> subProcess)', function() {
|
||||
|
||||
// when
|
||||
var connection = connect('Task_Top', 'SubProcess_Center'),
|
||||
source = connection.source,
|
||||
target = connection.target;
|
||||
|
||||
var expectedX = getMid(source).x;
|
||||
|
||||
// then
|
||||
expect(connection).to.have.waypoints([
|
||||
{ x: expectedX, y: source.y + source.height },
|
||||
{ x: expectedX, y: target.y }
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bpmn:definitions 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" id="Definitions_00dfyhw" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.7.1">
|
||||
<bpmn:process id="Process_00i7uqd" isExecutable="true">
|
||||
<bpmn:subProcess id="SubProcess_Center" />
|
||||
<bpmn:subProcess id="SubProcess_Bottom" />
|
||||
<bpmn:task id="Task_Right" />
|
||||
<bpmn:task id="Task_Top" />
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_00i7uqd">
|
||||
<bpmndi:BPMNShape id="Activity_0r2w32m_di" bpmnElement="SubProcess_Center" isExpanded="true">
|
||||
<dc:Bounds x="270" y="270" width="350" height="200" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0tbriov_di" bpmnElement="SubProcess_Bottom" isExpanded="true">
|
||||
<dc:Bounds x="160" y="600" width="350" height="200" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0fm36cc_di" bpmnElement="Task_Right">
|
||||
<dc:Bounds x="780" y="270" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_16fbgsj_di" bpmnElement="Task_Top">
|
||||
<dc:Bounds x="520" y="110" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
|
@ -6,7 +6,7 @@ import {
|
|||
/**
|
||||
* Create a fake key event for testing purposes.
|
||||
*
|
||||
* @param {String|Number} key the key or keyCode/charCode
|
||||
* @param {string|number} key the key or keyCode/charCode
|
||||
* @param {Object} [attrs]
|
||||
*
|
||||
* @return {Event}
|
||||
|
|
Loading…
Reference in New Issue