ElementRegistry.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  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 {string|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 {string|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. * Update the graphics of an element
  71. *
  72. * @param {string|djs.model.Base} element
  73. * @param {SVGElement} gfx
  74. * @param {boolean} [secondary=false] whether to update the secondary connected element
  75. */
  76. ElementRegistry.prototype.updateGraphics = function(filter, gfx, secondary) {
  77. var id = filter.id || filter;
  78. var container = this._elements[id];
  79. if (secondary) {
  80. container.secondaryGfx = gfx;
  81. } else {
  82. container.gfx = gfx;
  83. }
  84. if (gfx) {
  85. svgAttr(gfx, ELEMENT_ID, id);
  86. }
  87. return gfx;
  88. };
  89. /**
  90. * Return the model element for a given id or graphics.
  91. *
  92. * @example
  93. *
  94. * elementRegistry.get('SomeElementId_1');
  95. * elementRegistry.get(gfx);
  96. *
  97. *
  98. * @param {string|SVGElement} filter for selecting the element
  99. *
  100. * @return {djs.model.Base}
  101. */
  102. ElementRegistry.prototype.get = function(filter) {
  103. var id;
  104. if (typeof filter === 'string') {
  105. id = filter;
  106. } else {
  107. id = filter && svgAttr(filter, ELEMENT_ID);
  108. }
  109. var container = this._elements[id];
  110. return container && container.element;
  111. };
  112. /**
  113. * Return all elements that match a given filter function.
  114. *
  115. * @param {Function} fn
  116. *
  117. * @return {Array<djs.model.Base>}
  118. */
  119. ElementRegistry.prototype.filter = function(fn) {
  120. var filtered = [];
  121. this.forEach(function(element, gfx) {
  122. if (fn(element, gfx)) {
  123. filtered.push(element);
  124. }
  125. });
  126. return filtered;
  127. };
  128. /**
  129. * Return the first element that satisfies the provided testing function.
  130. *
  131. * @param {Function} fn
  132. *
  133. * @return {djs.model.Base}
  134. */
  135. ElementRegistry.prototype.find = function(fn) {
  136. var map = this._elements,
  137. keys = Object.keys(map);
  138. for (var i = 0; i < keys.length; i++) {
  139. var id = keys[i],
  140. container = map[id],
  141. element = container.element,
  142. gfx = container.gfx;
  143. if (fn(element, gfx)) {
  144. return element;
  145. }
  146. }
  147. };
  148. /**
  149. * Return all rendered model elements.
  150. *
  151. * @return {Array<djs.model.Base>}
  152. */
  153. ElementRegistry.prototype.getAll = function() {
  154. return this.filter(function(e) { return e; });
  155. };
  156. /**
  157. * Iterate over all diagram elements.
  158. *
  159. * @param {Function} fn
  160. */
  161. ElementRegistry.prototype.forEach = function(fn) {
  162. var map = this._elements;
  163. Object.keys(map).forEach(function(id) {
  164. var container = map[id],
  165. element = container.element,
  166. gfx = container.gfx;
  167. return fn(element, gfx);
  168. });
  169. };
  170. /**
  171. * Return the graphical representation of an element or its id.
  172. *
  173. * @example
  174. * elementRegistry.getGraphics('SomeElementId_1');
  175. * elementRegistry.getGraphics(rootElement); // <g ...>
  176. *
  177. * elementRegistry.getGraphics(rootElement, true); // <svg ...>
  178. *
  179. *
  180. * @param {string|djs.model.Base} filter
  181. * @param {boolean} [secondary=false] whether to return the secondary connected element
  182. *
  183. * @return {SVGElement}
  184. */
  185. ElementRegistry.prototype.getGraphics = function(filter, secondary) {
  186. var id = filter.id || filter;
  187. var container = this._elements[id];
  188. return container && (secondary ? container.secondaryGfx : container.gfx);
  189. };
  190. /**
  191. * Validate the suitability of the given id and signals a problem
  192. * with an exception.
  193. *
  194. * @param {string} id
  195. *
  196. * @throws {Error} if id is empty or already assigned
  197. */
  198. ElementRegistry.prototype._validateId = function(id) {
  199. if (!id) {
  200. throw new Error('element must have an id');
  201. }
  202. if (this._elements[id]) {
  203. throw new Error('element with id ' + id + ' already added');
  204. }
  205. };