SpaceToolPreview.js 6.8 KB

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