index.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. import { is, isAny } from '../../../utils/modelUtil';
  2. import { findFreePosition, generateGetNextPosition, getConnectedDistance } from '../../../autoPlace/YmAutoPlaceUtil';
  3. import { isObject } from 'min-dash';
  4. import { typeLabel, typeTrigger } from '../../../config/variableName';
  5. var HIGH_PRIORITY = 2000;
  6. function distance(a: any, b: any) {
  7. return Math.sqrt(Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2));
  8. }
  9. /**
  10. * Convert the given bounds to a { top, left, bottom, right } descriptor.
  11. * @param {Point|Rect} bounds
  12. * @return {RectTRBL}
  13. *
  14. */
  15. export function asTRBL(bounds: any) {
  16. return {
  17. top: bounds.y,
  18. right: bounds.x + (bounds.width || 0),
  19. bottom: bounds.y + (bounds.height || 0),
  20. left: bounds.x,
  21. };
  22. }
  23. export function getConnectionMid(connection: any) {
  24. var waypoints = connection.waypoints;
  25. var parts = waypoints.reduce(function (parts: any, point: any, index: any) {
  26. var lastPoint = waypoints[index - 1];
  27. if (lastPoint) {
  28. var lastPart = parts[parts.length - 1];
  29. var startLength = (lastPart && lastPart.endLength) || 0;
  30. var length = distance(lastPoint, point);
  31. parts.push({
  32. start: lastPoint,
  33. end: point,
  34. startLength: startLength,
  35. endLength: startLength + length,
  36. length: length,
  37. });
  38. }
  39. return parts;
  40. }, []);
  41. var totalLength = parts.reduce(function (length: any, part: any) {
  42. return length + part.length;
  43. }, 0);
  44. var midLength = totalLength / 2;
  45. var i = 0;
  46. var midSegment = parts[i];
  47. while (midSegment.endLength < midLength) {
  48. midSegment = parts[++i];
  49. }
  50. var segmentProgress = (midLength - midSegment.startLength) / midSegment.length;
  51. var midPoint = {
  52. x: midSegment.start.x + (midSegment.end.x - midSegment.start.x) * segmentProgress,
  53. y: midSegment.start.y + (midSegment.end.y - midSegment.start.y) * segmentProgress,
  54. };
  55. return midPoint;
  56. }
  57. export function roundPoint(point: any) {
  58. return {
  59. x: Math.round(point.x),
  60. y: Math.round(point.y),
  61. };
  62. }
  63. export function getBoundsMid(bounds: any) {
  64. return roundPoint({
  65. x: bounds.x + (bounds.width || 0) / 2,
  66. y: bounds.y + (bounds.height || 0) / 2,
  67. });
  68. }
  69. export function getMid(element: any) {
  70. if (!!element.waypoints) return getConnectionMid(element);
  71. return getBoundsMid(element);
  72. }
  73. export function getOrientation(rect: any, reference: any, padding: any) {
  74. padding = padding || 0;
  75. if (!isObject(padding)) padding = { x: padding, y: padding };
  76. var rectOrientation = asTRBL(rect),
  77. referenceOrientation = asTRBL(reference);
  78. var top = rectOrientation.bottom + padding.y <= referenceOrientation.top,
  79. right = rectOrientation.left - padding.x >= referenceOrientation.right,
  80. bottom = rectOrientation.top - padding.y >= referenceOrientation.bottom,
  81. left = rectOrientation.right + padding.x <= referenceOrientation.left;
  82. var vertical = top ? 'top' : bottom ? 'bottom' : null,
  83. horizontal = left ? 'left' : right ? 'right' : null;
  84. if (horizontal && vertical) return vertical + '-' + horizontal;
  85. else return horizontal || vertical || 'intersect';
  86. }
  87. /**
  88. * Always try to place element right of source;
  89. * compute actual distance from previous nodes in flow.
  90. */
  91. export function getFlowNodePosition(source: any, element: any) {
  92. var sourceTrbl = asTRBL(source); // 描述图形或区域在页面或画布上的位置和大小
  93. var sourceMid = getMid(source); // 获取中心点坐标
  94. var horizontalDistance = getConnectedDistance(source, {
  95. direction: 's',
  96. filter: function (connection: any) {
  97. return is(connection, 'bpmn:SequenceFlow');
  98. },
  99. });
  100. var margin = 30,
  101. minDistance = 50,
  102. orientation = 'top';
  103. if (is(source, 'bpmn:BoundaryEvent')) {
  104. orientation = getOrientation(source, source.host, -25);
  105. if (orientation.indexOf('top') !== -1) margin *= -1;
  106. }
  107. var position: any = {};
  108. position = {
  109. // x: sourceTrbl.right + horizontalDistance + element.width / 2,
  110. // y: sourceMid.y + getVerticalDistance(orientation, minDistance),
  111. x: sourceMid.x,
  112. y: sourceTrbl.bottom + horizontalDistance + element.height / 2,
  113. };
  114. // y轴距离
  115. var nextPositionDirection = {
  116. x: {
  117. margin: margin,
  118. minDistance: minDistance,
  119. },
  120. };
  121. return findFreePosition(source, element, position, generateGetNextPosition(nextPositionDirection));
  122. }
  123. export function getNewShapePosition(source: any, element: any) {
  124. if (is(element, 'bpmn:TextAnnotation')) return getTextAnnotationPosition(source, element);
  125. if (isAny(element, ['bpmn:DataObjectReference', 'bpmn:DataStoreReference'])) return getDataElementPosition(source, element);
  126. if (is(element, 'bpmn:FlowNode')) return getFlowNodePosition(source, element);
  127. }
  128. export function getDataElementPosition(source: any, element: any) {
  129. var sourceTrbl = asTRBL(source);
  130. var position = {
  131. x: sourceTrbl.right - 10 + element.width / 2,
  132. y: sourceTrbl.bottom + 40 + element.width / 2,
  133. };
  134. var nextPositionDirection = {
  135. x: {
  136. margin: 30,
  137. minDistance: 30,
  138. },
  139. };
  140. return findFreePosition(source, element, position, generateGetNextPosition(nextPositionDirection));
  141. }
  142. export function getTextAnnotationPosition(source: any, element: any) {
  143. var sourceTrbl = asTRBL(source);
  144. var position = {
  145. x: sourceTrbl.right + element.width / 2,
  146. y: sourceTrbl.top - 50 - element.height / 2,
  147. };
  148. if (!!source.waypoints) {
  149. position = getMid(source);
  150. position.x += 100;
  151. position.y -= 50;
  152. }
  153. var nextPositionDirection = {
  154. y: {
  155. margin: -30,
  156. minDistance: 20,
  157. },
  158. };
  159. return findFreePosition(source, element, position, generateGetNextPosition(nextPositionDirection));
  160. }
  161. function getNewSourceInLabel(source: any) {
  162. if (source.type === typeLabel) {
  163. let connectElement: any = source?.labelTarget;
  164. if (connectElement?.target) return connectElement.target;
  165. }
  166. return source;
  167. }
  168. export default function YmGridSnappingAutoPlaceBehavior(eventBus: any, injector: any) {
  169. eventBus.on('autoPlace', HIGH_PRIORITY, function (context: any) {
  170. var source = context.source,
  171. sourceMid = getMid(source),
  172. shape = context.shape;
  173. let elementRegistry = injector.get('elementRegistry');
  174. let element = elementRegistry.get(source.id);
  175. var position: any = getNewShapePosition(getNewSourceInLabel(element), shape);
  176. ['x', 'y'].forEach(function (axis: any) {
  177. var options: any = {};
  178. if (position[axis] === sourceMid[axis]) return;
  179. if (position[axis] > sourceMid[axis]) options.min = position[axis];
  180. else options.max = position[axis];
  181. if (is(shape, 'bpmn:TextAnnotation')) {
  182. if (isHorizontal(axis)) options.offset = -shape.width / 2;
  183. else options.offset = -shape.height / 2;
  184. }
  185. });
  186. let height = shape.wnType === typeTrigger ? 254 : 160;
  187. position = {
  188. x: position.x,
  189. y: Math.abs(position.y - element.y) > 260 ? element.y + height : position.y,
  190. };
  191. return position;
  192. });
  193. }
  194. YmGridSnappingAutoPlaceBehavior.$inject = ['eventBus', 'injector'];
  195. function isHorizontal(axis: any) {
  196. return axis === 'x';
  197. }