SpaceToolPreview.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. import {
  2. forEach
  3. } from 'min-dash';
  4. var MARKER_DRAGGING = 'djs-dragging',
  5. MARKER_RESIZING = 'djs-resizing';
  6. var LOW_PRIORITY = 250;
  7. import {
  8. append as svgAppend,
  9. attr as svgAttr,
  10. classes as svgClasses,
  11. create as svgCreate,
  12. remove as svgRemove
  13. } from 'tiny-svg';
  14. import {
  15. translate
  16. } from '../../util/SvgTransformUtil';
  17. var max = Math.max;
  18. /**
  19. * Provides previews for selecting/moving/resizing shapes when creating/removing space.
  20. *
  21. * @param {EventBus} eventBus
  22. * @param {ElementRegistry} elementRegistry
  23. * @param {Canvas} canvas
  24. * @param {Styles} styles
  25. */
  26. export default function SpaceToolPreview(
  27. eventBus, elementRegistry, canvas,
  28. styles, previewSupport) {
  29. function addPreviewGfx(collection, dragGroup) {
  30. forEach(collection, function(element) {
  31. previewSupport.addDragger(element, dragGroup);
  32. canvas.addMarker(element, MARKER_DRAGGING);
  33. });
  34. }
  35. // add crosshair
  36. eventBus.on('spaceTool.selection.start', function(event) {
  37. var space = canvas.getLayer('space'),
  38. context = event.context;
  39. var orientation = {
  40. x: 'M 0,-10000 L 0,10000',
  41. y: 'M -10000,0 L 10000,0'
  42. };
  43. var crosshairGroup = svgCreate('g');
  44. svgAttr(crosshairGroup, styles.cls('djs-crosshair-group', [ 'no-events' ]));
  45. svgAppend(space, crosshairGroup);
  46. // horizontal path
  47. var pathX = svgCreate('path');
  48. svgAttr(pathX, 'd', orientation.x);
  49. svgClasses(pathX).add('djs-crosshair');
  50. svgAppend(crosshairGroup, pathX);
  51. // vertical path
  52. var pathY = svgCreate('path');
  53. svgAttr(pathY, 'd', orientation.y);
  54. svgClasses(pathY).add('djs-crosshair');
  55. svgAppend(crosshairGroup, pathY);
  56. context.crosshairGroup = crosshairGroup;
  57. });
  58. // update crosshair
  59. eventBus.on('spaceTool.selection.move', function(event) {
  60. var crosshairGroup = event.context.crosshairGroup;
  61. translate(crosshairGroup, event.x, event.y);
  62. });
  63. // remove crosshair
  64. eventBus.on('spaceTool.selection.cleanup', function(event) {
  65. var context = event.context,
  66. crosshairGroup = context.crosshairGroup;
  67. if (crosshairGroup) {
  68. svgRemove(crosshairGroup);
  69. }
  70. });
  71. // add and update move/resize previews
  72. eventBus.on('spaceTool.move', LOW_PRIORITY, function(event) {
  73. var context = event.context,
  74. line = context.line,
  75. axis = context.axis,
  76. movingShapes = context.movingShapes,
  77. resizingShapes = context.resizingShapes;
  78. if (!context.initialized) {
  79. return;
  80. }
  81. if (!context.dragGroup) {
  82. var spaceLayer = canvas.getLayer('space');
  83. line = svgCreate('path');
  84. svgAttr(line, 'd', 'M0,0 L0,0');
  85. svgClasses(line).add('djs-crosshair');
  86. svgAppend(spaceLayer, line);
  87. context.line = line;
  88. var dragGroup = svgCreate('g');
  89. svgAttr(dragGroup, styles.cls('djs-drag-group', [ 'no-events' ]));
  90. svgAppend(canvas.getActiveLayer(), dragGroup);
  91. // shapes
  92. addPreviewGfx(movingShapes, dragGroup);
  93. // connections
  94. var movingConnections = context.movingConnections = elementRegistry.filter(function(element) {
  95. var sourceIsMoving = false;
  96. forEach(movingShapes, function(shape) {
  97. forEach(shape.outgoing, function(connection) {
  98. if (element === connection) {
  99. sourceIsMoving = true;
  100. }
  101. });
  102. });
  103. var targetIsMoving = false;
  104. forEach(movingShapes, function(shape) {
  105. forEach(shape.incoming, function(connection) {
  106. if (element === connection) {
  107. targetIsMoving = true;
  108. }
  109. });
  110. });
  111. var sourceIsResizing = false;
  112. forEach(resizingShapes, function(shape) {
  113. forEach(shape.outgoing, function(connection) {
  114. if (element === connection) {
  115. sourceIsResizing = true;
  116. }
  117. });
  118. });
  119. var targetIsResizing = false;
  120. forEach(resizingShapes, function(shape) {
  121. forEach(shape.incoming, function(connection) {
  122. if (element === connection) {
  123. targetIsResizing = true;
  124. }
  125. });
  126. });
  127. return isConnection(element)
  128. && (sourceIsMoving || sourceIsResizing)
  129. && (targetIsMoving || targetIsResizing);
  130. });
  131. addPreviewGfx(movingConnections, dragGroup);
  132. context.dragGroup = dragGroup;
  133. }
  134. if (!context.frameGroup) {
  135. var frameGroup = svgCreate('g');
  136. svgAttr(frameGroup, styles.cls('djs-frame-group', [ 'no-events' ]));
  137. svgAppend(canvas.getActiveLayer(), frameGroup);
  138. var frames = [];
  139. forEach(resizingShapes, function(shape) {
  140. var frame = previewSupport.addFrame(shape, frameGroup);
  141. var initialBounds = frame.getBBox();
  142. frames.push({
  143. element: frame,
  144. initialBounds: initialBounds
  145. });
  146. canvas.addMarker(shape, MARKER_RESIZING);
  147. });
  148. context.frameGroup = frameGroup;
  149. context.frames = frames;
  150. }
  151. var orientation = {
  152. x: 'M' + event.x + ', -10000 L' + event.x + ', 10000',
  153. y: 'M -10000, ' + event.y + ' L 10000, ' + event.y
  154. };
  155. svgAttr(line, { d: orientation[ axis ] });
  156. var opposite = { x: 'y', y: 'x' };
  157. var delta = { x: event.dx, y: event.dy };
  158. delta[ opposite[ context.axis ] ] = 0;
  159. // update move previews
  160. translate(context.dragGroup, delta.x, delta.y);
  161. // update resize previews
  162. forEach(context.frames, function(frame) {
  163. var element = frame.element,
  164. initialBounds = frame.initialBounds,
  165. width,
  166. height;
  167. if (context.direction === 'e') {
  168. svgAttr(element, {
  169. width: max(initialBounds.width + delta.x, 5)
  170. });
  171. } else {
  172. width = max(initialBounds.width - delta.x, 5);
  173. svgAttr(element, {
  174. width: width,
  175. x: initialBounds.x + initialBounds.width - width
  176. });
  177. }
  178. if (context.direction === 's') {
  179. svgAttr(element, {
  180. height: max(initialBounds.height + delta.y, 5)
  181. });
  182. } else {
  183. height = max(initialBounds.height - delta.y, 5);
  184. svgAttr(element, {
  185. height: height,
  186. y: initialBounds.y + initialBounds.height - height
  187. });
  188. }
  189. });
  190. });
  191. // remove move/resize previews
  192. eventBus.on('spaceTool.cleanup', function(event) {
  193. var context = event.context,
  194. movingShapes = context.movingShapes,
  195. movingConnections = context.movingConnections,
  196. resizingShapes = context.resizingShapes,
  197. line = context.line,
  198. dragGroup = context.dragGroup,
  199. frameGroup = context.frameGroup;
  200. // moving shapes
  201. forEach(movingShapes, function(shape) {
  202. canvas.removeMarker(shape, MARKER_DRAGGING);
  203. });
  204. // moving connections
  205. forEach(movingConnections, function(connection) {
  206. canvas.removeMarker(connection, MARKER_DRAGGING);
  207. });
  208. if (dragGroup) {
  209. svgRemove(line);
  210. svgRemove(dragGroup);
  211. }
  212. forEach(resizingShapes, function(shape) {
  213. canvas.removeMarker(shape, MARKER_RESIZING);
  214. });
  215. if (frameGroup) {
  216. svgRemove(frameGroup);
  217. }
  218. });
  219. }
  220. SpaceToolPreview.$inject = [
  221. 'eventBus',
  222. 'elementRegistry',
  223. 'canvas',
  224. 'styles',
  225. 'previewSupport'
  226. ];
  227. // helpers //////////////////////
  228. /**
  229. * Checks if an element is a connection.
  230. */
  231. function isConnection(element) {
  232. return element.waypoints;
  233. }