ResizeHandles.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. import {
  2. bind,
  3. forEach
  4. } from 'min-dash';
  5. import {
  6. append as svgAppend,
  7. attr as svgAttr,
  8. classes as svgClasses,
  9. clear as svgClear,
  10. create as svgCreate
  11. } from 'tiny-svg';
  12. import {
  13. event as domEvent
  14. } from 'min-dom';
  15. import {
  16. isPrimaryButton
  17. } from '../../util/Mouse';
  18. import {
  19. transform
  20. } from '../../util/SvgTransformUtil';
  21. import { getReferencePoint } from './Resize';
  22. var HANDLE_OFFSET = -6,
  23. HANDLE_SIZE = 8,
  24. HANDLE_HIT_SIZE = 20;
  25. var CLS_RESIZER = 'djs-resizer';
  26. var directions = [ 'n', 'w', 's', 'e', 'nw', 'ne', 'se', 'sw' ];
  27. /**
  28. * This component is responsible for adding resize handles.
  29. *
  30. * @param {EventBus} eventBus
  31. * @param {Canvas} canvas
  32. * @param {Selection} selection
  33. * @param {Resize} resize
  34. */
  35. export default function ResizeHandles(eventBus, canvas, selection, resize) {
  36. this._resize = resize;
  37. this._canvas = canvas;
  38. var self = this;
  39. eventBus.on('selection.changed', function(e) {
  40. var newSelection = e.newSelection;
  41. // remove old selection markers
  42. self.removeResizers();
  43. // add new selection markers ONLY if single selection
  44. if (newSelection.length === 1) {
  45. forEach(newSelection, bind(self.addResizer, self));
  46. }
  47. });
  48. eventBus.on('shape.changed', function(e) {
  49. var shape = e.element;
  50. if (selection.isSelected(shape)) {
  51. self.removeResizers();
  52. self.addResizer(shape);
  53. }
  54. });
  55. }
  56. ResizeHandles.prototype.makeDraggable = function(element, gfx, direction) {
  57. var resize = this._resize;
  58. function startResize(event) {
  59. // only trigger on left mouse button
  60. if (isPrimaryButton(event)) {
  61. resize.activate(event, element, direction);
  62. }
  63. }
  64. domEvent.bind(gfx, 'mousedown', startResize);
  65. domEvent.bind(gfx, 'touchstart', startResize);
  66. };
  67. ResizeHandles.prototype._createResizer = function(element, x, y, direction) {
  68. var resizersParent = this._getResizersParent();
  69. var offset = getHandleOffset(direction);
  70. var group = svgCreate('g');
  71. svgClasses(group).add(CLS_RESIZER);
  72. svgClasses(group).add(CLS_RESIZER + '-' + element.id);
  73. svgClasses(group).add(CLS_RESIZER + '-' + direction);
  74. svgAppend(resizersParent, group);
  75. var visual = svgCreate('rect');
  76. svgAttr(visual, {
  77. x: -HANDLE_SIZE / 2 + offset.x,
  78. y: -HANDLE_SIZE / 2 + offset.y,
  79. width: HANDLE_SIZE,
  80. height: HANDLE_SIZE
  81. });
  82. svgClasses(visual).add(CLS_RESIZER + '-visual');
  83. svgAppend(group, visual);
  84. var hit = svgCreate('rect');
  85. svgAttr(hit, {
  86. x: -HANDLE_HIT_SIZE / 2 + offset.x,
  87. y: -HANDLE_HIT_SIZE / 2 + offset.y,
  88. width: HANDLE_HIT_SIZE,
  89. height: HANDLE_HIT_SIZE
  90. });
  91. svgClasses(hit).add(CLS_RESIZER + '-hit');
  92. svgAppend(group, hit);
  93. transform(group, x, y);
  94. return group;
  95. };
  96. ResizeHandles.prototype.createResizer = function(element, direction) {
  97. var point = getReferencePoint(element, direction);
  98. var resizer = this._createResizer(element, point.x, point.y, direction);
  99. this.makeDraggable(element, resizer, direction);
  100. };
  101. // resize handles implementation ///////////////////////////////
  102. /**
  103. * Add resizers for a given element.
  104. *
  105. * @param {djs.model.Element} element
  106. */
  107. ResizeHandles.prototype.addResizer = function(element) {
  108. var self = this;
  109. if (isConnection(element) || !this._resize.canResize({ shape: element })) {
  110. return;
  111. }
  112. forEach(directions, function(direction) {
  113. self.createResizer(element, direction);
  114. });
  115. };
  116. /**
  117. * Remove all resizers
  118. */
  119. ResizeHandles.prototype.removeResizers = function() {
  120. var resizersParent = this._getResizersParent();
  121. svgClear(resizersParent);
  122. };
  123. ResizeHandles.prototype._getResizersParent = function() {
  124. return this._canvas.getLayer('resizers');
  125. };
  126. ResizeHandles.$inject = [
  127. 'eventBus',
  128. 'canvas',
  129. 'selection',
  130. 'resize'
  131. ];
  132. // helpers //////////
  133. function getHandleOffset(direction) {
  134. var offset = {
  135. x: 0,
  136. y: 0
  137. };
  138. if (direction.indexOf('e') !== -1) {
  139. offset.x = -HANDLE_OFFSET;
  140. } else if (direction.indexOf('w') !== -1) {
  141. offset.x = HANDLE_OFFSET;
  142. }
  143. if (direction.indexOf('s') !== -1) {
  144. offset.y = -HANDLE_OFFSET;
  145. } else if (direction.indexOf('n') !== -1) {
  146. offset.y = HANDLE_OFFSET;
  147. }
  148. return offset;
  149. }
  150. function isConnection(element) {
  151. return !!element.waypoints;
  152. }