SelectionVisuals.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import {
  2. assign,
  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 { getBBox } from '../../util/Elements';
  13. var MARKER_HOVER = 'hover',
  14. MARKER_SELECTED = 'selected';
  15. var SELECTION_OUTLINE_PADDING = 6;
  16. /**
  17. * A plugin that adds a visible selection UI to shapes and connections
  18. * by appending the <code>hover</code> and <code>selected</code> classes to them.
  19. *
  20. * @class
  21. *
  22. * Makes elements selectable, too.
  23. *
  24. * @param {Canvas} canvas
  25. * @param {EventBus} eventBus
  26. */
  27. export default function SelectionVisuals(canvas, eventBus, selection) {
  28. this._canvas = canvas;
  29. var self = this;
  30. this._multiSelectionBox = null;
  31. function addMarker(e, cls) {
  32. canvas.addMarker(e, cls);
  33. }
  34. function removeMarker(e, cls) {
  35. canvas.removeMarker(e, cls);
  36. }
  37. eventBus.on('element.hover', function(event) {
  38. addMarker(event.element, MARKER_HOVER);
  39. });
  40. eventBus.on('element.out', function(event) {
  41. removeMarker(event.element, MARKER_HOVER);
  42. });
  43. eventBus.on('selection.changed', function(event) {
  44. function deselect(s) {
  45. removeMarker(s, MARKER_SELECTED);
  46. }
  47. function select(s) {
  48. addMarker(s, MARKER_SELECTED);
  49. }
  50. var oldSelection = event.oldSelection,
  51. newSelection = event.newSelection;
  52. forEach(oldSelection, function(e) {
  53. if (newSelection.indexOf(e) === -1) {
  54. deselect(e);
  55. }
  56. });
  57. forEach(newSelection, function(e) {
  58. if (oldSelection.indexOf(e) === -1) {
  59. select(e);
  60. }
  61. });
  62. self._updateSelectionOutline(newSelection);
  63. });
  64. eventBus.on('element.changed', function(event) {
  65. if (selection.isSelected(event.element)) {
  66. self._updateSelectionOutline(selection.get());
  67. }
  68. });
  69. }
  70. SelectionVisuals.$inject = [
  71. 'canvas',
  72. 'eventBus',
  73. 'selection'
  74. ];
  75. SelectionVisuals.prototype._updateSelectionOutline = function(selection) {
  76. var layer = this._canvas.getLayer('selectionOutline');
  77. svgClear(layer);
  78. var enabled = selection.length > 1;
  79. var container = this._canvas.getContainer();
  80. svgClasses(container)[enabled ? 'add' : 'remove']('djs-multi-select');
  81. if (!enabled) {
  82. return;
  83. }
  84. var bBox = addSelectionOutlinePadding(getBBox(selection));
  85. var rect = svgCreate('rect');
  86. svgAttr(rect, assign({
  87. rx: 3
  88. }, bBox));
  89. svgClasses(rect).add('djs-selection-outline');
  90. svgAppend(layer, rect);
  91. };
  92. // helpers //////////
  93. function addSelectionOutlinePadding(bBox) {
  94. return {
  95. x: bBox.x - SELECTION_OUTLINE_PADDING,
  96. y: bBox.y - SELECTION_OUTLINE_PADDING,
  97. width: bBox.width + SELECTION_OUTLINE_PADDING * 2,
  98. height: bBox.height + SELECTION_OUTLINE_PADDING * 2
  99. };
  100. }