BpmnOrderingProvider.js 3.9 KB

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