Diagram.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. import { Injector } from 'didi';
  2. import CoreModule from './core';
  3. /**
  4. * Bootstrap an injector from a list of modules, instantiating a number of default components
  5. *
  6. * @ignore
  7. * @param {Array<didi.Module>} bootstrapModules
  8. *
  9. * @return {didi.Injector} a injector to use to access the components
  10. */
  11. function bootstrap(bootstrapModules) {
  12. var modules = [],
  13. components = [];
  14. function hasModule(m) {
  15. return modules.indexOf(m) >= 0;
  16. }
  17. function addModule(m) {
  18. modules.push(m);
  19. }
  20. function visit(m) {
  21. if (hasModule(m)) {
  22. return;
  23. }
  24. (m.__depends__ || []).forEach(visit);
  25. if (hasModule(m)) {
  26. return;
  27. }
  28. addModule(m);
  29. (m.__init__ || []).forEach(function(c) {
  30. components.push(c);
  31. });
  32. }
  33. bootstrapModules.forEach(visit);
  34. var injector = new Injector(modules);
  35. components.forEach(function(c) {
  36. try {
  37. // eagerly resolve component (fn or string)
  38. injector[typeof c === 'string' ? 'get' : 'invoke'](c);
  39. } catch (e) {
  40. console.error('Failed to instantiate component');
  41. console.error(e.stack);
  42. throw e;
  43. }
  44. });
  45. return injector;
  46. }
  47. /**
  48. * Creates an injector from passed options.
  49. *
  50. * @ignore
  51. * @param {Object} options
  52. * @return {didi.Injector}
  53. */
  54. function createInjector(options) {
  55. options = options || {};
  56. var configModule = {
  57. 'config': ['value', options]
  58. };
  59. var modules = [ configModule, CoreModule ].concat(options.modules || []);
  60. return bootstrap(modules);
  61. }
  62. /**
  63. * The main diagram-js entry point that bootstraps the diagram with the given
  64. * configuration.
  65. *
  66. * To register extensions with the diagram, pass them as Array<didi.Module> to the constructor.
  67. *
  68. * @class djs.Diagram
  69. * @memberOf djs
  70. * @constructor
  71. *
  72. * @example
  73. *
  74. * <caption>Creating a plug-in that logs whenever a shape is added to the canvas.</caption>
  75. *
  76. * // plug-in implemenentation
  77. * function MyLoggingPlugin(eventBus) {
  78. * eventBus.on('shape.added', function(event) {
  79. * console.log('shape ', event.shape, ' was added to the diagram');
  80. * });
  81. * }
  82. *
  83. * // export as module
  84. * export default {
  85. * __init__: [ 'myLoggingPlugin' ],
  86. * myLoggingPlugin: [ 'type', MyLoggingPlugin ]
  87. * };
  88. *
  89. *
  90. * // instantiate the diagram with the new plug-in
  91. *
  92. * import MyLoggingModule from 'path-to-my-logging-plugin';
  93. *
  94. * var diagram = new Diagram({
  95. * modules: [
  96. * MyLoggingModule
  97. * ]
  98. * });
  99. *
  100. * diagram.invoke([ 'canvas', function(canvas) {
  101. * // add shape to drawing canvas
  102. * canvas.addShape({ x: 10, y: 10 });
  103. * });
  104. *
  105. * // 'shape ... was added to the diagram' logged to console
  106. *
  107. * @param {Object} options
  108. * @param {Array<didi.Module>} [options.modules] external modules to instantiate with the diagram
  109. * @param {didi.Injector} [injector] an (optional) injector to bootstrap the diagram with
  110. */
  111. export default function Diagram(options, injector) {
  112. // create injector unless explicitly specified
  113. this.injector = injector = injector || createInjector(options);
  114. // API
  115. /**
  116. * Resolves a diagram service
  117. *
  118. * @method Diagram#get
  119. *
  120. * @param {String} name the name of the diagram service to be retrieved
  121. * @param {Boolean} [strict=true] if false, resolve missing services to null
  122. */
  123. this.get = injector.get;
  124. /**
  125. * Executes a function into which diagram services are injected
  126. *
  127. * @method Diagram#invoke
  128. *
  129. * @param {Function|Object[]} fn the function to resolve
  130. * @param {Object} locals a number of locals to use to resolve certain dependencies
  131. */
  132. this.invoke = injector.invoke;
  133. // init
  134. // indicate via event
  135. /**
  136. * An event indicating that all plug-ins are loaded.
  137. *
  138. * Use this event to fire other events to interested plug-ins
  139. *
  140. * @memberOf Diagram
  141. *
  142. * @event diagram.init
  143. *
  144. * @example
  145. *
  146. * eventBus.on('diagram.init', function() {
  147. * eventBus.fire('my-custom-event', { foo: 'BAR' });
  148. * });
  149. *
  150. * @type {Object}
  151. */
  152. this.get('eventBus').fire('diagram.init');
  153. }
  154. /**
  155. * Destroys the diagram
  156. *
  157. * @method Diagram#destroy
  158. */
  159. Diagram.prototype.destroy = function() {
  160. this.get('eventBus').fire('diagram.destroy');
  161. };
  162. /**
  163. * Clear the diagram, removing all contents.
  164. */
  165. Diagram.prototype.clear = function() {
  166. this.get('eventBus').fire('diagram.clear');
  167. };