LassoTool.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. import { values } from 'min-dash';
  2. import { getEnclosedElements } from '../../util/Elements';
  3. import {
  4. hasSecondaryModifier
  5. } from '../../util/Mouse';
  6. import {
  7. append as svgAppend,
  8. attr as svgAttr,
  9. create as svgCreate,
  10. remove as svgRemove
  11. } from 'tiny-svg';
  12. var LASSO_TOOL_CURSOR = 'crosshair';
  13. export default function LassoTool(
  14. eventBus, canvas, dragging,
  15. elementRegistry, selection, toolManager,
  16. mouse) {
  17. this._selection = selection;
  18. this._dragging = dragging;
  19. this._mouse = mouse;
  20. var self = this;
  21. // lasso visuals implementation
  22. /**
  23. * A helper that realizes the selection box visual
  24. */
  25. var visuals = {
  26. create: function(context) {
  27. var container = canvas.getActiveLayer(),
  28. frame;
  29. frame = context.frame = svgCreate('rect');
  30. svgAttr(frame, {
  31. class: 'djs-lasso-overlay',
  32. width: 1,
  33. height: 1,
  34. x: 0,
  35. y: 0
  36. });
  37. svgAppend(container, frame);
  38. },
  39. update: function(context) {
  40. var frame = context.frame,
  41. bbox = context.bbox;
  42. svgAttr(frame, {
  43. x: bbox.x,
  44. y: bbox.y,
  45. width: bbox.width,
  46. height: bbox.height
  47. });
  48. },
  49. remove: function(context) {
  50. if (context.frame) {
  51. svgRemove(context.frame);
  52. }
  53. }
  54. };
  55. toolManager.registerTool('lasso', {
  56. tool: 'lasso.selection',
  57. dragging: 'lasso'
  58. });
  59. eventBus.on('lasso.selection.end', function(event) {
  60. var target = event.originalEvent.target;
  61. // only reactive on diagram click
  62. // on some occasions, event.hover is not set and we have to check if the target is an svg
  63. if (!event.hover && !(target instanceof SVGElement)) {
  64. return;
  65. }
  66. eventBus.once('lasso.selection.ended', function() {
  67. self.activateLasso(event.originalEvent, true);
  68. });
  69. });
  70. // lasso interaction implementation
  71. eventBus.on('lasso.end', function(event) {
  72. var bbox = toBBox(event);
  73. var elements = elementRegistry.filter(function(element) {
  74. return element;
  75. });
  76. self.select(elements, bbox);
  77. });
  78. eventBus.on('lasso.start', function(event) {
  79. var context = event.context;
  80. context.bbox = toBBox(event);
  81. visuals.create(context);
  82. });
  83. eventBus.on('lasso.move', function(event) {
  84. var context = event.context;
  85. context.bbox = toBBox(event);
  86. visuals.update(context);
  87. });
  88. eventBus.on('lasso.cleanup', function(event) {
  89. var context = event.context;
  90. visuals.remove(context);
  91. });
  92. // event integration
  93. eventBus.on('element.mousedown', 1500, function(event) {
  94. if (!hasSecondaryModifier(event)) {
  95. return;
  96. }
  97. self.activateLasso(event.originalEvent);
  98. // we've handled the event
  99. return true;
  100. });
  101. }
  102. LassoTool.$inject = [
  103. 'eventBus',
  104. 'canvas',
  105. 'dragging',
  106. 'elementRegistry',
  107. 'selection',
  108. 'toolManager',
  109. 'mouse'
  110. ];
  111. LassoTool.prototype.activateLasso = function(event, autoActivate) {
  112. this._dragging.init(event, 'lasso', {
  113. autoActivate: autoActivate,
  114. cursor: LASSO_TOOL_CURSOR,
  115. data: {
  116. context: {}
  117. }
  118. });
  119. };
  120. LassoTool.prototype.activateSelection = function(event, autoActivate) {
  121. this._dragging.init(event, 'lasso.selection', {
  122. trapClick: false,
  123. autoActivate: autoActivate,
  124. cursor: LASSO_TOOL_CURSOR,
  125. data: {
  126. context: {}
  127. }
  128. });
  129. };
  130. LassoTool.prototype.select = function(elements, bbox) {
  131. var selectedElements = getEnclosedElements(elements, bbox);
  132. this._selection.select(values(selectedElements));
  133. };
  134. LassoTool.prototype.toggle = function() {
  135. if (this.isActive()) {
  136. return this._dragging.cancel();
  137. }
  138. var mouseEvent = this._mouse.getLastMoveEvent();
  139. this.activateSelection(mouseEvent, !!mouseEvent);
  140. };
  141. LassoTool.prototype.isActive = function() {
  142. var context = this._dragging.context();
  143. return context && /^lasso/.test(context.prefix);
  144. };
  145. function toBBox(event) {
  146. var start = {
  147. x: event.x - event.dx,
  148. y: event.y - event.dy
  149. };
  150. var end = {
  151. x: event.x,
  152. y: event.y
  153. };
  154. var bbox;
  155. if ((start.x <= end.x && start.y < end.y) ||
  156. (start.x < end.x && start.y <= end.y)) {
  157. bbox = {
  158. x: start.x,
  159. y: start.y,
  160. width: end.x - start.x,
  161. height: end.y - start.y
  162. };
  163. } else if ((start.x >= end.x && start.y < end.y) ||
  164. (start.x > end.x && start.y <= end.y)) {
  165. bbox = {
  166. x: end.x,
  167. y: start.y,
  168. width: start.x - end.x,
  169. height: end.y - start.y
  170. };
  171. } else if ((start.x <= end.x && start.y > end.y) ||
  172. (start.x < end.x && start.y >= end.y)) {
  173. bbox = {
  174. x: start.x,
  175. y: end.y,
  176. width: end.x - start.x,
  177. height: start.y - end.y
  178. };
  179. } else if ((start.x >= end.x && start.y > end.y) ||
  180. (start.x > end.x && start.y >= end.y)) {
  181. bbox = {
  182. x: end.x,
  183. y: end.y,
  184. width: start.x - end.x,
  185. height: start.y - end.y
  186. };
  187. } else {
  188. bbox = {
  189. x: end.x,
  190. y: end.y,
  191. width: 0,
  192. height: 0
  193. };
  194. }
  195. return bbox;
  196. }