| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 |
- import { asBounds, asTRBL } from 'diagram-js/lib/layout/LayoutUtil';
- import { is, isAny } from '../../util/ModelUtil';
- /**
- * @typedef {import('diagram-js/lib/core/EventBus').default} EventBus
- * @typedef {import('../../model/Types').Moddle} Moddle
- *
- * @typedef {import('../../model/Types').Element} Element
- * @typedef {import('../../model/Types').Shape} Shape
- *
- * @typedef {import('diagram-js/lib/core/Canvas').CanvasPlane} CanvasPlane
- *
- * @typedef {import('diagram-js/lib/util/Types').Rect} Rect
- */
- var DEFAULT_POSITION = {
- x: 180,
- y: 160
- };
- /**
- * Hook into `import.render.start` and create new planes for diagrams with
- * collapsed subprocesses and all DI elements on the same plane.
- *
- * @param {EventBus} eventBus
- * @param {Moddle} moddle
- */
- export default function SubprocessCompatibility(eventBus, moddle) {
- this._eventBus = eventBus;
- this._moddle = moddle;
- var self = this;
- eventBus.on('import.render.start', 1500, function(e, context) {
- self._handleImport(context.definitions);
- });
- }
- /**
- * @param {ModdleElement} definitions
- */
- SubprocessCompatibility.prototype._handleImport = function(definitions) {
- if (!definitions.diagrams) {
- return;
- }
- var self = this;
- this._definitions = definitions;
- this._processToDiagramMap = {};
- definitions.diagrams.forEach(function(diagram) {
- if (!diagram.plane || !diagram.plane.bpmnElement) {
- return;
- }
- self._processToDiagramMap[diagram.plane.bpmnElement.id] = diagram;
- });
- var newDiagrams = [];
- definitions.diagrams.forEach(function(diagram) {
- var createdDiagrams = self._createNewDiagrams(diagram.plane);
- Array.prototype.push.apply(newDiagrams, createdDiagrams);
- });
- newDiagrams.forEach(function(diagram) {
- self._movePlaneElementsToOrigin(diagram.plane);
- });
- };
- /**
- * Moves all DI elements from collapsed subprocesses to a new plane.
- *
- * @param {CanvasPlane} plane
- *
- * @return {ModdleElement[]} new diagrams created for the collapsed subprocesses
- */
- SubprocessCompatibility.prototype._createNewDiagrams = function(plane) {
- var self = this;
- var collapsedElements = [];
- var elementsToMove = [];
- plane.get('planeElement').forEach(function(diElement) {
- var businessObject = diElement.bpmnElement;
- if (!businessObject) {
- return;
- }
- var parent = businessObject.$parent;
- if (is(businessObject, 'bpmn:SubProcess') && !diElement.isExpanded) {
- collapsedElements.push(businessObject);
- }
- if (shouldMoveToPlane(businessObject, plane)) {
- // don't change the array while we iterate over it
- elementsToMove.push({ diElement: diElement, parent: parent });
- }
- });
- var newDiagrams = [];
- // create new planes for all collapsed subprocesses, even when they are empty
- collapsedElements.forEach(function(element) {
- if (!self._processToDiagramMap[ element.id ]) {
- var diagram = self._createDiagram(element);
- self._processToDiagramMap[element.id] = diagram;
- newDiagrams.push(diagram);
- }
- });
- elementsToMove.forEach(function(element) {
- var diElement = element.diElement;
- var parent = element.parent;
- // parent is expanded, get nearest collapsed parent
- while (parent && collapsedElements.indexOf(parent) === -1) {
- parent = parent.$parent;
- }
- // false positive, all parents are expanded
- if (!parent) {
- return;
- }
- var diagram = self._processToDiagramMap[ parent.id ];
- self._moveToDiPlane(diElement, diagram.plane);
- });
- return newDiagrams;
- };
- /**
- * @param {CanvasPlane} plane
- */
- SubprocessCompatibility.prototype._movePlaneElementsToOrigin = function(plane) {
- var elements = plane.get('planeElement');
- // get bounding box of all elements
- var planeBounds = getPlaneBounds(plane);
- var offset = {
- x: planeBounds.x - DEFAULT_POSITION.x,
- y: planeBounds.y - DEFAULT_POSITION.y
- };
- elements.forEach(function(diElement) {
- if (diElement.waypoint) {
- diElement.waypoint.forEach(function(waypoint) {
- waypoint.x = waypoint.x - offset.x;
- waypoint.y = waypoint.y - offset.y;
- });
- } else if (diElement.bounds) {
- diElement.bounds.x = diElement.bounds.x - offset.x;
- diElement.bounds.y = diElement.bounds.y - offset.y;
- }
- });
- };
- /**
- * @param {ModdleElement} diElement
- * @param {CanvasPlane} newPlane
- */
- SubprocessCompatibility.prototype._moveToDiPlane = function(diElement, newPlane) {
- var containingDiagram = findRootDiagram(diElement);
- // remove DI from old Plane and add it to the new one
- var parentPlaneElement = containingDiagram.plane.get('planeElement');
- parentPlaneElement.splice(parentPlaneElement.indexOf(diElement), 1);
- newPlane.get('planeElement').push(diElement);
- };
- /**
- * @param {ModdleElement} businessObject
- *
- * @return {ModdleElement}
- */
- SubprocessCompatibility.prototype._createDiagram = function(businessObject) {
- var plane = this._moddle.create('bpmndi:BPMNPlane', {
- bpmnElement: businessObject
- });
- var diagram = this._moddle.create('bpmndi:BPMNDiagram', {
- plane: plane
- });
- plane.$parent = diagram;
- plane.bpmnElement = businessObject;
- diagram.$parent = this._definitions;
- this._definitions.diagrams.push(diagram);
- return diagram;
- };
- SubprocessCompatibility.$inject = [ 'eventBus', 'moddle' ];
- // helpers //////////
- function findRootDiagram(element) {
- if (is(element, 'bpmndi:BPMNDiagram')) {
- return element;
- } else {
- return findRootDiagram(element.$parent);
- }
- }
- /**
- * @param {CanvasPlane} plane
- *
- * @return {Rect}
- */
- function getPlaneBounds(plane) {
- var planeTrbl = {
- top: Infinity,
- right: -Infinity,
- bottom: -Infinity,
- left: Infinity
- };
- plane.planeElement.forEach(function(element) {
- if (!element.bounds) {
- return;
- }
- var trbl = asTRBL(element.bounds);
- planeTrbl.top = Math.min(trbl.top, planeTrbl.top);
- planeTrbl.left = Math.min(trbl.left, planeTrbl.left);
- });
- return asBounds(planeTrbl);
- }
- /**
- * @param {ModdleElement} businessObject
- * @param {CanvasPlane} plane
- *
- * @return {boolean}
- */
- function shouldMoveToPlane(businessObject, plane) {
- var parent = businessObject.$parent;
- // don't move elements that are already on the plane
- if (!is(parent, 'bpmn:SubProcess') || parent === plane.bpmnElement) {
- return false;
- }
- // dataAssociations are children of the subprocess but rendered on process level
- // cf. https://github.com/bpmn-io/bpmn-js/issues/1619
- if (isAny(businessObject, [ 'bpmn:DataInputAssociation', 'bpmn:DataOutputAssociation' ])) {
- return false;
- }
- return true;
- }
|