BpmnOrderingProvider.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. import inherits from 'inherits-browser';
  2. import OrderingProvider from 'diagram-js/lib/features/ordering/OrderingProvider';
  3. import {
  4. isAny
  5. } from '../modeling/util/ModelingUtil';
  6. import {
  7. findIndex,
  8. find
  9. } from 'min-dash';
  10. /**
  11. * @typedef {import('diagram-js/lib/core/Canvas').default} Canvas
  12. * @typedef {import('diagram-js/lib/core/EventBus').default} EventBus
  13. * @typedef {import('diagram-js/i18n/translate/translate').default} Translate
  14. */
  15. /**
  16. * A BPMN-specific ordering provider.
  17. *
  18. * @param {EventBus} eventBus
  19. * @param {Canvas} canvas
  20. * @param {Translate} translate
  21. */
  22. export default function BpmnOrderingProvider(eventBus, canvas, translate) {
  23. OrderingProvider.call(this, eventBus);
  24. var orders = [
  25. { type: 'bpmn:SubProcess', order: { level: 6 } },
  26. // handle SequenceFlow(s) like message flows and render them always on top
  27. {
  28. type: 'bpmn:SequenceFlow',
  29. order: {
  30. level: 9,
  31. containers: [
  32. 'bpmn:Participant',
  33. 'bpmn:FlowElementsContainer'
  34. ]
  35. }
  36. },
  37. // handle DataAssociation(s) like message flows and render them always on top
  38. {
  39. type: 'bpmn:DataAssociation',
  40. order: {
  41. level: 9,
  42. containers: [
  43. 'bpmn:Collaboration',
  44. 'bpmn:FlowElementsContainer'
  45. ]
  46. }
  47. },
  48. {
  49. type: 'bpmn:MessageFlow', order: {
  50. level: 9,
  51. containers: [ 'bpmn:Collaboration' ]
  52. }
  53. },
  54. {
  55. type: 'bpmn:Association',
  56. order: {
  57. level: 6,
  58. containers: [
  59. 'bpmn:Participant',
  60. 'bpmn:FlowElementsContainer',
  61. 'bpmn:Collaboration'
  62. ]
  63. }
  64. },
  65. { type: 'bpmn:BoundaryEvent', order: { level: 8 } },
  66. {
  67. type: 'bpmn:Group',
  68. order: {
  69. level: 10,
  70. containers: [
  71. 'bpmn:Collaboration',
  72. 'bpmn:FlowElementsContainer'
  73. ]
  74. }
  75. },
  76. { type: 'bpmn:FlowElement', order: { level: 5 } },
  77. { type: 'bpmn:Participant', order: { level: -2 } },
  78. { type: 'bpmn:Lane', order: { level: -1 } }
  79. ];
  80. function computeOrder(element) {
  81. if (element.labelTarget) {
  82. return { level: 10 };
  83. }
  84. var entry = find(orders, function(o) {
  85. return isAny(element, [ o.type ]);
  86. });
  87. return entry && entry.order || { level: 1 };
  88. }
  89. function getOrder(element) {
  90. var order = element.order;
  91. if (!order) {
  92. element.order = order = computeOrder(element);
  93. }
  94. if (!order) {
  95. throw new Error('no order for <' + element.id + '>');
  96. }
  97. return order;
  98. }
  99. function findActualParent(element, newParent, containers) {
  100. var actualParent = newParent;
  101. while (actualParent) {
  102. if (isAny(actualParent, containers)) {
  103. break;
  104. }
  105. actualParent = actualParent.parent;
  106. }
  107. if (!actualParent) {
  108. throw new Error('no parent for <' + element.id + '> in <' + (newParent && newParent.id) + '>');
  109. }
  110. return actualParent;
  111. }
  112. this.getOrdering = function(element, newParent) {
  113. // render labels always on top
  114. if (element.labelTarget) {
  115. return {
  116. parent: canvas.findRoot(newParent) || canvas.getRootElement(),
  117. index: -1
  118. };
  119. }
  120. var elementOrder = getOrder(element);
  121. if (elementOrder.containers) {
  122. newParent = findActualParent(element, newParent, elementOrder.containers);
  123. }
  124. var currentIndex = newParent.children.indexOf(element);
  125. var insertIndex = findIndex(newParent.children, function(child) {
  126. // do not compare with labels, they are created
  127. // in the wrong order (right after elements) during import and
  128. // mess up the positioning.
  129. if (!element.labelTarget && child.labelTarget) {
  130. return false;
  131. }
  132. return elementOrder.level < getOrder(child).level;
  133. });
  134. // if the element is already in the child list at
  135. // a smaller index, we need to adjust the insert index.
  136. // this takes into account that the element is being removed
  137. // before being re-inserted
  138. if (insertIndex !== -1) {
  139. if (currentIndex !== -1 && currentIndex < insertIndex) {
  140. insertIndex -= 1;
  141. }
  142. }
  143. return {
  144. index: insertIndex,
  145. parent: newParent
  146. };
  147. };
  148. }
  149. BpmnOrderingProvider.$inject = [ 'eventBus', 'canvas', 'translate' ];
  150. inherits(BpmnOrderingProvider, OrderingProvider);