LabelSupport.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import {
  2. forEach,
  3. filter
  4. } from 'min-dash';
  5. import inherits from 'inherits';
  6. var LOW_PRIORITY = 250,
  7. HIGH_PRIORITY = 1400;
  8. import {
  9. add as collectionAdd,
  10. indexOf as collectionIdx
  11. } from '../../util/Collections';
  12. import { saveClear } from '../../util/Removal';
  13. import CommandInterceptor from '../../command/CommandInterceptor';
  14. /**
  15. * A handler that makes sure labels are properly moved with
  16. * their label targets.
  17. *
  18. * @param {didi.Injector} injector
  19. * @param {EventBus} eventBus
  20. * @param {Modeling} modeling
  21. */
  22. export default function LabelSupport(injector, eventBus, modeling) {
  23. CommandInterceptor.call(this, eventBus);
  24. var movePreview = injector.get('movePreview', false);
  25. // remove labels from the collection that are being
  26. // moved with other elements anyway
  27. eventBus.on('shape.move.start', HIGH_PRIORITY, function(e) {
  28. var context = e.context,
  29. shapes = context.shapes,
  30. validatedShapes = context.validatedShapes;
  31. context.shapes = removeLabels(shapes);
  32. context.validatedShapes = removeLabels(validatedShapes);
  33. });
  34. // add labels to visual's group
  35. movePreview && eventBus.on('shape.move.start', LOW_PRIORITY, function(e) {
  36. var context = e.context,
  37. shapes = context.shapes;
  38. var labels = [];
  39. forEach(shapes, function(element) {
  40. forEach(element.labels, function(label) {
  41. if (!label.hidden && context.shapes.indexOf(label) === -1) {
  42. labels.push(label);
  43. }
  44. if (element.labelTarget) {
  45. labels.push(element);
  46. }
  47. });
  48. });
  49. forEach(labels, function(label) {
  50. movePreview.makeDraggable(context, label, true);
  51. });
  52. });
  53. // add all labels to move closure
  54. this.preExecuted('elements.move', HIGH_PRIORITY, function(e) {
  55. var context = e.context,
  56. closure = context.closure,
  57. enclosedElements = closure.enclosedElements;
  58. var enclosedLabels = [];
  59. // find labels that are not part of
  60. // move closure yet and add them
  61. forEach(enclosedElements, function(element) {
  62. forEach(element.labels, function(label) {
  63. if (!enclosedElements[label.id]) {
  64. enclosedLabels.push(label);
  65. }
  66. });
  67. });
  68. closure.addAll(enclosedLabels);
  69. });
  70. this.preExecute([
  71. 'connection.delete',
  72. 'shape.delete'
  73. ], function(e) {
  74. var context = e.context,
  75. element = context.connection || context.shape;
  76. saveClear(element.labels, function(label) {
  77. modeling.removeShape(label, { nested: true });
  78. });
  79. });
  80. this.execute('shape.delete', function(e) {
  81. var context = e.context,
  82. shape = context.shape,
  83. labelTarget = shape.labelTarget;
  84. // unset labelTarget
  85. if (labelTarget) {
  86. context.labelTargetIndex = collectionIdx(labelTarget.labels, shape);
  87. context.labelTarget = labelTarget;
  88. shape.labelTarget = null;
  89. }
  90. });
  91. this.revert('shape.delete', function(e) {
  92. var context = e.context,
  93. shape = context.shape,
  94. labelTarget = context.labelTarget,
  95. labelTargetIndex = context.labelTargetIndex;
  96. // restore labelTarget
  97. if (labelTarget) {
  98. collectionAdd(labelTarget.labels, shape, labelTargetIndex);
  99. shape.labelTarget = labelTarget;
  100. }
  101. });
  102. }
  103. inherits(LabelSupport, CommandInterceptor);
  104. LabelSupport.$inject = [
  105. 'injector',
  106. 'eventBus',
  107. 'modeling'
  108. ];
  109. /**
  110. * Return a filtered list of elements that do not
  111. * contain attached elements with hosts being part
  112. * of the selection.
  113. *
  114. * @param {Array<djs.model.Base>} elements
  115. *
  116. * @return {Array<djs.model.Base>} filtered
  117. */
  118. function removeLabels(elements) {
  119. return filter(elements, function(element) {
  120. // filter out labels that are move together
  121. // with their label targets
  122. return elements.indexOf(element.labelTarget) === -1;
  123. });
  124. }