Modeling.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. import { forEach } from 'min-dash';
  2. import {
  3. Base
  4. } from '../../model';
  5. import AppendShapeHandler from './cmd/AppendShapeHandler';
  6. import CreateShapeHandler from './cmd/CreateShapeHandler';
  7. import DeleteShapeHandler from './cmd/DeleteShapeHandler';
  8. import MoveShapeHandler from './cmd/MoveShapeHandler';
  9. import ResizeShapeHandler from './cmd/ResizeShapeHandler';
  10. import ReplaceShapeHandler from './cmd/ReplaceShapeHandler';
  11. import ToggleShapeCollapseHandler from './cmd/ToggleShapeCollapseHandler';
  12. import SpaceToolHandler from './cmd/SpaceToolHandler';
  13. import CreateLabelHandler from './cmd/CreateLabelHandler';
  14. import CreateConnectionHandler from './cmd/CreateConnectionHandler';
  15. import DeleteConnectionHandler from './cmd/DeleteConnectionHandler';
  16. import MoveConnectionHandler from './cmd/MoveConnectionHandler';
  17. import LayoutConnectionHandler from './cmd/LayoutConnectionHandler';
  18. import UpdateWaypointsHandler from './cmd/UpdateWaypointsHandler';
  19. import ReconnectConnectionHandler from './cmd/ReconnectConnectionHandler';
  20. import MoveElementsHandler from './cmd/MoveElementsHandler';
  21. import DeleteElementsHandler from './cmd/DeleteElementsHandler';
  22. import DistributeElementsHandler from './cmd/DistributeElementsHandler';
  23. import AlignElementsHandler from './cmd/AlignElementsHandler';
  24. import UpdateAttachmentHandler from './cmd/UpdateAttachmentHandler';
  25. import PasteHandler from './cmd/PasteHandler';
  26. /**
  27. * The basic modeling entry point.
  28. *
  29. * @param {EventBus} eventBus
  30. * @param {ElementFactory} elementFactory
  31. * @param {CommandStack} commandStack
  32. */
  33. export default function Modeling(eventBus, elementFactory, commandStack) {
  34. this._eventBus = eventBus;
  35. this._elementFactory = elementFactory;
  36. this._commandStack = commandStack;
  37. var self = this;
  38. eventBus.on('diagram.init', function() {
  39. // register modeling handlers
  40. self.registerHandlers(commandStack);
  41. });
  42. }
  43. Modeling.$inject = [ 'eventBus', 'elementFactory', 'commandStack' ];
  44. Modeling.prototype.getHandlers = function() {
  45. return {
  46. 'shape.append': AppendShapeHandler,
  47. 'shape.create': CreateShapeHandler,
  48. 'shape.delete': DeleteShapeHandler,
  49. 'shape.move': MoveShapeHandler,
  50. 'shape.resize': ResizeShapeHandler,
  51. 'shape.replace': ReplaceShapeHandler,
  52. 'shape.toggleCollapse': ToggleShapeCollapseHandler,
  53. 'spaceTool': SpaceToolHandler,
  54. 'label.create': CreateLabelHandler,
  55. 'connection.create': CreateConnectionHandler,
  56. 'connection.delete': DeleteConnectionHandler,
  57. 'connection.move': MoveConnectionHandler,
  58. 'connection.layout': LayoutConnectionHandler,
  59. 'connection.updateWaypoints': UpdateWaypointsHandler,
  60. 'connection.reconnectStart': ReconnectConnectionHandler,
  61. 'connection.reconnectEnd': ReconnectConnectionHandler,
  62. 'elements.move': MoveElementsHandler,
  63. 'elements.delete': DeleteElementsHandler,
  64. 'elements.distribute': DistributeElementsHandler,
  65. 'elements.align': AlignElementsHandler,
  66. 'element.updateAttachment': UpdateAttachmentHandler,
  67. 'elements.paste': PasteHandler
  68. };
  69. };
  70. /**
  71. * Register handlers with the command stack
  72. *
  73. * @param {CommandStack} commandStack
  74. */
  75. Modeling.prototype.registerHandlers = function(commandStack) {
  76. forEach(this.getHandlers(), function(handler, id) {
  77. commandStack.registerHandler(id, handler);
  78. });
  79. };
  80. // modeling helpers //////////////////////
  81. Modeling.prototype.moveShape = function(shape, delta, newParent, newParentIndex, hints) {
  82. if (typeof newParentIndex === 'object') {
  83. hints = newParentIndex;
  84. newParentIndex = null;
  85. }
  86. var context = {
  87. shape: shape,
  88. delta: delta,
  89. newParent: newParent,
  90. newParentIndex: newParentIndex,
  91. hints: hints || {}
  92. };
  93. this._commandStack.execute('shape.move', context);
  94. };
  95. /**
  96. * Update the attachment of the given shape.
  97. *
  98. * @param {djs.mode.Base} shape
  99. * @param {djs.model.Base} [newHost]
  100. */
  101. Modeling.prototype.updateAttachment = function(shape, newHost) {
  102. var context = {
  103. shape: shape,
  104. newHost: newHost
  105. };
  106. this._commandStack.execute('element.updateAttachment', context);
  107. };
  108. /**
  109. * Move a number of shapes to a new target, either setting it as
  110. * the new parent or attaching it.
  111. *
  112. * @param {Array<djs.mode.Base>} shapes
  113. * @param {Point} delta
  114. * @param {djs.model.Base} [target]
  115. * @param {Object} [hints]
  116. * @param {Boolean} [hints.attach=false]
  117. */
  118. Modeling.prototype.moveElements = function(shapes, delta, target, hints) {
  119. hints = hints || {};
  120. var attach = hints.attach;
  121. var newParent = target,
  122. newHost;
  123. if (attach === true) {
  124. newHost = target;
  125. newParent = target.parent;
  126. } else
  127. if (attach === false) {
  128. newHost = null;
  129. }
  130. var context = {
  131. shapes: shapes,
  132. delta: delta,
  133. newParent: newParent,
  134. newHost: newHost,
  135. hints: hints
  136. };
  137. this._commandStack.execute('elements.move', context);
  138. };
  139. Modeling.prototype.moveConnection = function(connection, delta, newParent, newParentIndex, hints) {
  140. if (typeof newParentIndex === 'object') {
  141. hints = newParentIndex;
  142. newParentIndex = undefined;
  143. }
  144. var context = {
  145. connection: connection,
  146. delta: delta,
  147. newParent: newParent,
  148. newParentIndex: newParentIndex,
  149. hints: hints || {}
  150. };
  151. this._commandStack.execute('connection.move', context);
  152. };
  153. Modeling.prototype.layoutConnection = function(connection, hints) {
  154. var context = {
  155. connection: connection,
  156. hints: hints || {}
  157. };
  158. this._commandStack.execute('connection.layout', context);
  159. };
  160. /**
  161. * Create connection.
  162. *
  163. * @param {djs.model.Base} source
  164. * @param {djs.model.Base} target
  165. * @param {Number} [targetIndex]
  166. * @param {Object|djs.model.Connection} connection
  167. * @param {djs.model.Base} parent
  168. * @param {Object} hints
  169. *
  170. * @return {djs.model.Connection} the created connection.
  171. */
  172. Modeling.prototype.createConnection = function(source, target, parentIndex, connection, parent, hints) {
  173. if (typeof parentIndex === 'object') {
  174. hints = parent;
  175. parent = connection;
  176. connection = parentIndex;
  177. parentIndex = undefined;
  178. }
  179. connection = this._create('connection', connection);
  180. var context = {
  181. source: source,
  182. target: target,
  183. parent: parent,
  184. parentIndex: parentIndex,
  185. connection: connection,
  186. hints: hints
  187. };
  188. this._commandStack.execute('connection.create', context);
  189. return context.connection;
  190. };
  191. /**
  192. * Create a shape at the specified position.
  193. *
  194. * @param {djs.model.Shape|Object} shape
  195. * @param {Point} position
  196. * @param {djs.model.Shape|djs.model.Root} target
  197. * @param {Number} [parentIndex] position in parents children list
  198. * @param {Object} [hints]
  199. * @param {Boolean} [hints.attach] whether to attach to target or become a child
  200. *
  201. * @return {djs.model.Shape} the created shape
  202. */
  203. Modeling.prototype.createShape = function(shape, position, target, parentIndex, hints) {
  204. if (typeof parentIndex !== 'number') {
  205. hints = parentIndex;
  206. parentIndex = undefined;
  207. }
  208. hints = hints || {};
  209. var attach = hints.attach,
  210. parent,
  211. host;
  212. shape = this._create('shape', shape);
  213. if (attach) {
  214. parent = target.parent;
  215. host = target;
  216. } else {
  217. parent = target;
  218. }
  219. var context = {
  220. position: position,
  221. shape: shape,
  222. parent: parent,
  223. parentIndex: parentIndex,
  224. host: host,
  225. hints: hints
  226. };
  227. this._commandStack.execute('shape.create', context);
  228. return context.shape;
  229. };
  230. Modeling.prototype.createLabel = function(labelTarget, position, label, parent) {
  231. label = this._create('label', label);
  232. var context = {
  233. labelTarget: labelTarget,
  234. position: position,
  235. parent: parent || labelTarget.parent,
  236. shape: label
  237. };
  238. this._commandStack.execute('label.create', context);
  239. return context.shape;
  240. };
  241. /**
  242. * Append shape to given source, drawing a connection
  243. * between source and the newly created shape.
  244. *
  245. * @param {djs.model.Shape} source
  246. * @param {djs.model.Shape|Object} shape
  247. * @param {Point} position
  248. * @param {djs.model.Shape} target
  249. * @param {Object} [hints]
  250. * @param {Boolean} [hints.attach]
  251. * @param {djs.model.Connection|Object} [hints.connection]
  252. * @param {djs.model.Base} [hints.connectionParent]
  253. *
  254. * @return {djs.model.Shape} the newly created shape
  255. */
  256. Modeling.prototype.appendShape = function(source, shape, position, target, hints) {
  257. hints = hints || {};
  258. shape = this._create('shape', shape);
  259. var context = {
  260. source: source,
  261. position: position,
  262. target: target,
  263. shape: shape,
  264. connection: hints.connection,
  265. connectionParent: hints.connectionParent,
  266. attach: hints.attach
  267. };
  268. this._commandStack.execute('shape.append', context);
  269. return context.shape;
  270. };
  271. Modeling.prototype.removeElements = function(elements) {
  272. var context = {
  273. elements: elements
  274. };
  275. this._commandStack.execute('elements.delete', context);
  276. };
  277. Modeling.prototype.distributeElements = function(groups, axis, dimension) {
  278. var context = {
  279. groups: groups,
  280. axis: axis,
  281. dimension: dimension
  282. };
  283. this._commandStack.execute('elements.distribute', context);
  284. };
  285. Modeling.prototype.removeShape = function(shape, hints) {
  286. var context = {
  287. shape: shape,
  288. hints: hints || {}
  289. };
  290. this._commandStack.execute('shape.delete', context);
  291. };
  292. Modeling.prototype.removeConnection = function(connection, hints) {
  293. var context = {
  294. connection: connection,
  295. hints: hints || {}
  296. };
  297. this._commandStack.execute('connection.delete', context);
  298. };
  299. Modeling.prototype.replaceShape = function(oldShape, newShape, hints) {
  300. var context = {
  301. oldShape: oldShape,
  302. newData: newShape,
  303. hints: hints || {}
  304. };
  305. this._commandStack.execute('shape.replace', context);
  306. return context.newShape;
  307. };
  308. Modeling.prototype.pasteElements = function(tree, topParent, position) {
  309. var context = {
  310. tree: tree,
  311. topParent: topParent,
  312. position: position
  313. };
  314. this._commandStack.execute('elements.paste', context);
  315. };
  316. Modeling.prototype.alignElements = function(elements, alignment) {
  317. var context = {
  318. elements: elements,
  319. alignment: alignment
  320. };
  321. this._commandStack.execute('elements.align', context);
  322. };
  323. Modeling.prototype.resizeShape = function(shape, newBounds, minBounds) {
  324. var context = {
  325. shape: shape,
  326. newBounds: newBounds,
  327. minBounds: minBounds
  328. };
  329. this._commandStack.execute('shape.resize', context);
  330. };
  331. Modeling.prototype.createSpace = function(movingShapes, resizingShapes, delta, direction) {
  332. var context = {
  333. movingShapes: movingShapes,
  334. resizingShapes: resizingShapes,
  335. delta: delta,
  336. direction: direction
  337. };
  338. this._commandStack.execute('spaceTool', context);
  339. };
  340. Modeling.prototype.updateWaypoints = function(connection, newWaypoints, hints) {
  341. var context = {
  342. connection: connection,
  343. newWaypoints: newWaypoints,
  344. hints: hints || {}
  345. };
  346. this._commandStack.execute('connection.updateWaypoints', context);
  347. };
  348. Modeling.prototype.reconnectStart = function(connection, newSource, dockingOrPoints) {
  349. var context = {
  350. connection: connection,
  351. newSource: newSource,
  352. dockingOrPoints: dockingOrPoints
  353. };
  354. this._commandStack.execute('connection.reconnectStart', context);
  355. };
  356. Modeling.prototype.reconnectEnd = function(connection, newTarget, dockingOrPoints) {
  357. var context = {
  358. connection: connection,
  359. newTarget: newTarget,
  360. dockingOrPoints: dockingOrPoints
  361. };
  362. this._commandStack.execute('connection.reconnectEnd', context);
  363. };
  364. Modeling.prototype.connect = function(source, target, attrs, hints) {
  365. return this.createConnection(source, target, attrs || {}, source.parent, hints);
  366. };
  367. Modeling.prototype._create = function(type, attrs) {
  368. if (attrs instanceof Base) {
  369. return attrs;
  370. } else {
  371. return this._elementFactory.create(type, attrs);
  372. }
  373. };
  374. Modeling.prototype.toggleCollapse = function(shape, hints) {
  375. var context = {
  376. shape: shape,
  377. hints: hints || {}
  378. };
  379. this._commandStack.execute('shape.toggleCollapse', context);
  380. };