ElementRegistry.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. var ELEMENT_ID = 'data-element-id';
  2. import { attr as svgAttr } from 'tiny-svg';
  3. /**
  4. * @class
  5. *
  6. * A registry that keeps track of all shapes in the diagram.
  7. */
  8. export default function ElementRegistry(eventBus) {
  9. this._elements = {};
  10. this._eventBus = eventBus;
  11. }
  12. ElementRegistry.$inject = [ 'eventBus' ];
  13. /**
  14. * Register a pair of (element, gfx, (secondaryGfx)).
  15. *
  16. * @param {djs.model.Base} element
  17. * @param {SVGElement} gfx
  18. * @param {SVGElement} [secondaryGfx] optional other element to register, too
  19. */
  20. ElementRegistry.prototype.add = function(element, gfx, secondaryGfx) {
  21. var id = element.id;
  22. this._validateId(id);
  23. // associate dom node with element
  24. svgAttr(gfx, ELEMENT_ID, id);
  25. if (secondaryGfx) {
  26. svgAttr(secondaryGfx, ELEMENT_ID, id);
  27. }
  28. this._elements[id] = { element: element, gfx: gfx, secondaryGfx: secondaryGfx };
  29. };
  30. /**
  31. * Removes an element from the registry.
  32. *
  33. * @param {djs.model.Base} element
  34. */
  35. ElementRegistry.prototype.remove = function(element) {
  36. var elements = this._elements,
  37. id = element.id || element,
  38. container = id && elements[id];
  39. if (container) {
  40. // unset element id on gfx
  41. svgAttr(container.gfx, ELEMENT_ID, '');
  42. if (container.secondaryGfx) {
  43. svgAttr(container.secondaryGfx, ELEMENT_ID, '');
  44. }
  45. delete elements[id];
  46. }
  47. };
  48. /**
  49. * Update the id of an element
  50. *
  51. * @param {djs.model.Base} element
  52. * @param {String} newId
  53. */
  54. ElementRegistry.prototype.updateId = function(element, newId) {
  55. this._validateId(newId);
  56. if (typeof element === 'string') {
  57. element = this.get(element);
  58. }
  59. this._eventBus.fire('element.updateId', {
  60. element: element,
  61. newId: newId
  62. });
  63. var gfx = this.getGraphics(element),
  64. secondaryGfx = this.getGraphics(element, true);
  65. this.remove(element);
  66. element.id = newId;
  67. this.add(element, gfx, secondaryGfx);
  68. };
  69. /**
  70. * Return the model element for a given id or graphics.
  71. *
  72. * @example
  73. *
  74. * elementRegistry.get('SomeElementId_1');
  75. * elementRegistry.get(gfx);
  76. *
  77. *
  78. * @param {String|SVGElement} filter for selecting the element
  79. *
  80. * @return {djs.model.Base}
  81. */
  82. ElementRegistry.prototype.get = function(filter) {
  83. var id;
  84. if (typeof filter === 'string') {
  85. id = filter;
  86. } else {
  87. id = filter && svgAttr(filter, ELEMENT_ID);
  88. }
  89. var container = this._elements[id];
  90. return container && container.element;
  91. };
  92. /**
  93. * Return all elements that match a given filter function.
  94. *
  95. * @param {Function} fn
  96. *
  97. * @return {Array<djs.model.Base>}
  98. */
  99. ElementRegistry.prototype.filter = function(fn) {
  100. var filtered = [];
  101. this.forEach(function(element, gfx) {
  102. if (fn(element, gfx)) {
  103. filtered.push(element);
  104. }
  105. });
  106. return filtered;
  107. };
  108. /**
  109. * Return all rendered model elements.
  110. *
  111. * @return {Array<djs.model.Base>}
  112. */
  113. ElementRegistry.prototype.getAll = function() {
  114. return this.filter(function(e) { return e; });
  115. };
  116. /**
  117. * Iterate over all diagram elements.
  118. *
  119. * @param {Function} fn
  120. */
  121. ElementRegistry.prototype.forEach = function(fn) {
  122. var map = this._elements;
  123. Object.keys(map).forEach(function(id) {
  124. var container = map[id],
  125. element = container.element,
  126. gfx = container.gfx;
  127. return fn(element, gfx);
  128. });
  129. };
  130. /**
  131. * Return the graphical representation of an element or its id.
  132. *
  133. * @example
  134. * elementRegistry.getGraphics('SomeElementId_1');
  135. * elementRegistry.getGraphics(rootElement); // <g ...>
  136. *
  137. * elementRegistry.getGraphics(rootElement, true); // <svg ...>
  138. *
  139. *
  140. * @param {String|djs.model.Base} filter
  141. * @param {Boolean} [secondary=false] whether to return the secondary connected element
  142. *
  143. * @return {SVGElement}
  144. */
  145. ElementRegistry.prototype.getGraphics = function(filter, secondary) {
  146. var id = filter.id || filter;
  147. var container = this._elements[id];
  148. return container && (secondary ? container.secondaryGfx : container.gfx);
  149. };
  150. /**
  151. * Validate the suitability of the given id and signals a problem
  152. * with an exception.
  153. *
  154. * @param {String} id
  155. *
  156. * @throws {Error} if id is empty or already assigned
  157. */
  158. ElementRegistry.prototype._validateId = function(id) {
  159. if (!id) {
  160. throw new Error('element must have an id');
  161. }
  162. if (this._elements[id]) {
  163. throw new Error('element with id ' + id + ' already added');
  164. }
  165. };