vis.js is a dynamic, browser-based visualization library
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

715 lines
26 KiB

  1. var util = require('../../util');
  2. var Node = require('../Node');
  3. var Edge = require('../Edge');
  4. var Hammer = require('../../module/hammer');
  5. var hammerUtil = require('../../hammerUtil');
  6. /**
  7. * clears the toolbar div element of children
  8. *
  9. * @private
  10. */
  11. exports._clearManipulatorBar = function() {
  12. this._recursiveDOMDelete(this.manipulationDiv);
  13. this.manipulationDOM = {};
  14. this._cleanManipulatorHammers();
  15. this._manipulationReleaseOverload = function () {};
  16. delete this.body.sectors['support']['nodes']['targetNode'];
  17. delete this.body.sectors['support']['nodes']['targetViaNode'];
  18. this.controlNodesActive = false;
  19. this.freezeSimulationEnabled = false;
  20. };
  21. exports._cleanManipulatorHammers = function() {
  22. // clean hammer bindings
  23. if (this.manipulationHammers.length != 0) {
  24. for (var i = 0; i < this.manipulationHammers.length; i++) {
  25. this.manipulationHammers[i].destroy();
  26. }
  27. this.manipulationHammers = [];
  28. }
  29. };
  30. /**
  31. * Manipulation UI temporarily overloads certain functions to extend or replace them. To be able to restore
  32. * these functions to their original functionality, we saved them in this.cachedFunctions.
  33. * This function restores these functions to their original function.
  34. *
  35. * @private
  36. */
  37. exports._restoreOverloadedFunctions = function() {
  38. for (var functionName in this.cachedFunctions) {
  39. if (this.cachedFunctions.hasOwnProperty(functionName)) {
  40. this[functionName] = this.cachedFunctions[functionName];
  41. delete this.cachedFunctions[functionName];
  42. }
  43. }
  44. };
  45. /**
  46. * Enable or disable edit-mode.
  47. *
  48. * @private
  49. */
  50. exports._toggleEditMode = function() {
  51. this.editMode = !this.editMode;
  52. var toolbar = this.manipulationDiv;
  53. var closeDiv = this.closeDiv;
  54. var editModeDiv = this.editModeDiv;
  55. if (this.editMode == true) {
  56. toolbar.style.display="block";
  57. closeDiv.style.display="block";
  58. editModeDiv.style.display="none";
  59. this._bindHammerToDiv(closeDiv,'_toggleEditMode');
  60. }
  61. else {
  62. toolbar.style.display="none";
  63. closeDiv.style.display="none";
  64. editModeDiv.style.display="block";
  65. }
  66. this._createManipulatorBar()
  67. };
  68. /**
  69. * main function, creates the main toolbar. Removes functions bound to the select event. Binds all the buttons of the toolbar.
  70. *
  71. * @private
  72. */
  73. exports._createManipulatorBar = function() {
  74. // remove bound functions
  75. if (this.boundFunction) {
  76. this.off('select', this.boundFunction);
  77. }
  78. this._cleanManipulatorHammers();
  79. var locale = this.constants.locales[this.constants.locale];
  80. if (this.edgeBeingEdited !== undefined) {
  81. this.edgeBeingEdited._disableControlNodes();
  82. this.edgeBeingEdited = undefined;
  83. this.selectedControlNode = null;
  84. this.controlNodesActive = false;
  85. this._redraw();
  86. }
  87. // restore overloaded functions
  88. this._restoreOverloadedFunctions();
  89. // resume calculation
  90. this.freezeSimulation(false);
  91. // reset global variables
  92. this.blockConnectingEdgeSelection = false;
  93. this.forceAppendSelection = false;
  94. this.manipulationDOM = {};
  95. if (this.editMode == true) {
  96. while (this.manipulationDiv.hasChildNodes()) {
  97. this.manipulationDiv.removeChild(this.manipulationDiv.firstChild);
  98. }
  99. this.manipulationDOM['addNodeSpan'] = document.createElement('div');
  100. this.manipulationDOM['addNodeSpan'].className = 'network-manipulationUI add';
  101. this.manipulationDOM['addNodeLabelSpan'] = document.createElement('div');
  102. this.manipulationDOM['addNodeLabelSpan'].className = 'network-manipulationLabel';
  103. this.manipulationDOM['addNodeLabelSpan'].innerHTML = locale['addNode'];
  104. this.manipulationDOM['addNodeSpan'].appendChild(this.manipulationDOM['addNodeLabelSpan']);
  105. this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div');
  106. this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine';
  107. this.manipulationDOM['addEdgeSpan'] = document.createElement('div');
  108. this.manipulationDOM['addEdgeSpan'].className = 'network-manipulationUI connect';
  109. this.manipulationDOM['addEdgeLabelSpan'] = document.createElement('div');
  110. this.manipulationDOM['addEdgeLabelSpan'].className = 'network-manipulationLabel';
  111. this.manipulationDOM['addEdgeLabelSpan'].innerHTML = locale['addEdge'];
  112. this.manipulationDOM['addEdgeSpan'].appendChild(this.manipulationDOM['addEdgeLabelSpan']);
  113. this.manipulationDiv.appendChild(this.manipulationDOM['addNodeSpan']);
  114. this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']);
  115. this.manipulationDiv.appendChild(this.manipulationDOM['addEdgeSpan']);
  116. if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) {
  117. this.manipulationDOM['seperatorLineDiv2'] = document.createElement('div');
  118. this.manipulationDOM['seperatorLineDiv2'].className = 'network-seperatorLine';
  119. this.manipulationDOM['editNodeSpan'] = document.createElement('div');
  120. this.manipulationDOM['editNodeSpan'].className = 'network-manipulationUI edit';
  121. this.manipulationDOM['editNodeLabelSpan'] = document.createElement('div');
  122. this.manipulationDOM['editNodeLabelSpan'].className = 'network-manipulationLabel';
  123. this.manipulationDOM['editNodeLabelSpan'].innerHTML = locale['editNode'];
  124. this.manipulationDOM['editNodeSpan'].appendChild(this.manipulationDOM['editNodeLabelSpan']);
  125. this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv2']);
  126. this.manipulationDiv.appendChild(this.manipulationDOM['editNodeSpan']);
  127. }
  128. else if (this._getSelectedEdgeCount() == 1 && this._getSelectedNodeCount() == 0) {
  129. this.manipulationDOM['seperatorLineDiv3'] = document.createElement('div');
  130. this.manipulationDOM['seperatorLineDiv3'].className = 'network-seperatorLine';
  131. this.manipulationDOM['editEdgeSpan'] = document.createElement('div');
  132. this.manipulationDOM['editEdgeSpan'].className = 'network-manipulationUI edit';
  133. this.manipulationDOM['editEdgeLabelSpan'] = document.createElement('div');
  134. this.manipulationDOM['editEdgeLabelSpan'].className = 'network-manipulationLabel';
  135. this.manipulationDOM['editEdgeLabelSpan'].innerHTML = locale['editEdge'];
  136. this.manipulationDOM['editEdgeSpan'].appendChild(this.manipulationDOM['editEdgeLabelSpan']);
  137. this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv3']);
  138. this.manipulationDiv.appendChild(this.manipulationDOM['editEdgeSpan']);
  139. }
  140. if (this._selectionIsEmpty() == false) {
  141. this.manipulationDOM['seperatorLineDiv4'] = document.createElement('div');
  142. this.manipulationDOM['seperatorLineDiv4'].className = 'network-seperatorLine';
  143. this.manipulationDOM['deleteSpan'] = document.createElement('div');
  144. this.manipulationDOM['deleteSpan'].className = 'network-manipulationUI delete';
  145. this.manipulationDOM['deleteLabelSpan'] = document.createElement('div');
  146. this.manipulationDOM['deleteLabelSpan'].className = 'network-manipulationLabel';
  147. this.manipulationDOM['deleteLabelSpan'].innerHTML = locale['del'];
  148. this.manipulationDOM['deleteSpan'].appendChild(this.manipulationDOM['deleteLabelSpan']);
  149. this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv4']);
  150. this.manipulationDiv.appendChild(this.manipulationDOM['deleteSpan']);
  151. }
  152. // bind the icons
  153. this._bindHammerToDiv(this.manipulationDOM['addNodeSpan'],'_createAddNodeToolbar');
  154. this._bindHammerToDiv(this.manipulationDOM['addEdgeSpan'],'_createAddEdgeToolbar');
  155. this._bindHammerToDiv(this.closeDiv,'_toggleEditMode');
  156. if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) {
  157. this._bindHammerToDiv(this.manipulationDOM['editNodeSpan'],'_editNode');
  158. }
  159. else if (this._getSelectedEdgeCount() == 1 && this._getSelectedNodeCount() == 0) {
  160. this._bindHammerToDiv(this.manipulationDOM['editEdgeSpan'],'_createEditEdgeToolbar');
  161. }
  162. if (this._selectionIsEmpty() == false) {
  163. this._bindHammerToDiv(this.manipulationDOM['deleteSpan'],'_deleteSelected');
  164. }
  165. var me = this;
  166. this.boundFunction = me._createManipulatorBar;
  167. this.on('select', this.boundFunction);
  168. }
  169. else {
  170. while (this.editModeDiv.hasChildNodes()) {
  171. this.editModeDiv.removeChild(this.editModeDiv.firstChild);
  172. }
  173. this.manipulationDOM['editModeSpan'] = document.createElement('div');
  174. this.manipulationDOM['editModeSpan'].className = 'network-manipulationUI edit editmode';
  175. this.manipulationDOM['editModeLabelSpan'] = document.createElement('div');
  176. this.manipulationDOM['editModeLabelSpan'].className = 'network-manipulationLabel';
  177. this.manipulationDOM['editModeLabelSpan'].innerHTML = locale['edit'];
  178. this.manipulationDOM['editModeSpan'].appendChild(this.manipulationDOM['editModeLabelSpan']);
  179. this.editModeDiv.appendChild(this.manipulationDOM['editModeSpan']);
  180. this._bindHammerToDiv(this.manipulationDOM['editModeSpan'],'_toggleEditMode');
  181. }
  182. };
  183. exports._bindHammerToDiv = function(domElement, funct) {
  184. var hammer = new Hammer(domElement, {});
  185. hammerUtil.onTouch(hammer, this[funct].bind(this));
  186. this.manipulationHammers.push(hammer);
  187. };
  188. /**
  189. * Create the toolbar for adding Nodes
  190. *
  191. * @private
  192. */
  193. exports._createAddNodeToolbar = function() {
  194. // clear the toolbar
  195. this._clearManipulatorBar();
  196. if (this.boundFunction) {
  197. this.off('select', this.boundFunction);
  198. }
  199. var locale = this.constants.locales[this.constants.locale];
  200. this.manipulationDOM = {};
  201. this.manipulationDOM['backSpan'] = document.createElement('div');
  202. this.manipulationDOM['backSpan'].className = 'network-manipulationUI back';
  203. this.manipulationDOM['backLabelSpan'] = document.createElement('div');
  204. this.manipulationDOM['backLabelSpan'].className = 'network-manipulationLabel';
  205. this.manipulationDOM['backLabelSpan'].innerHTML = locale['back'];
  206. this.manipulationDOM['backSpan'].appendChild(this.manipulationDOM['backLabelSpan']);
  207. this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div');
  208. this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine';
  209. this.manipulationDOM['descriptionSpan'] = document.createElement('div');
  210. this.manipulationDOM['descriptionSpan'].className = 'network-manipulationUI none';
  211. this.manipulationDOM['descriptionLabelSpan'] = document.createElement('div');
  212. this.manipulationDOM['descriptionLabelSpan'].className = 'network-manipulationLabel';
  213. this.manipulationDOM['descriptionLabelSpan'].innerHTML = locale['addDescription'];
  214. this.manipulationDOM['descriptionSpan'].appendChild(this.manipulationDOM['descriptionLabelSpan']);
  215. this.manipulationDiv.appendChild(this.manipulationDOM['backSpan']);
  216. this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']);
  217. this.manipulationDiv.appendChild(this.manipulationDOM['descriptionSpan']);
  218. // bind the icon
  219. this._bindHammerToDiv(this.manipulationDOM['backSpan'],'_createManipulatorBar');
  220. // we use the boundFunction so we can reference it when we unbind it from the "select" event.
  221. var me = this;
  222. this.boundFunction = me._addNode;
  223. this.on('select', this.boundFunction);
  224. };
  225. /**
  226. * create the toolbar to connect nodes
  227. *
  228. * @private
  229. */
  230. exports._createAddEdgeToolbar = function() {
  231. // clear the toolbar
  232. this._clearManipulatorBar();
  233. this._unselectAll(true);
  234. this.freezeSimulationEnabled = true;
  235. if (this.boundFunction) {
  236. this.off('select', this.boundFunction);
  237. }
  238. var locale = this.constants.locales[this.constants.locale];
  239. this.forceAppendSelection = false;
  240. this.blockConnectingEdgeSelection = true;
  241. this.manipulationDOM = {};
  242. this.manipulationDOM['backSpan'] = document.createElement('div');
  243. this.manipulationDOM['backSpan'].className = 'network-manipulationUI back';
  244. this.manipulationDOM['backLabelSpan'] = document.createElement('div');
  245. this.manipulationDOM['backLabelSpan'].className = 'network-manipulationLabel';
  246. this.manipulationDOM['backLabelSpan'].innerHTML = locale['back'];
  247. this.manipulationDOM['backSpan'].appendChild(this.manipulationDOM['backLabelSpan']);
  248. this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div');
  249. this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine';
  250. this.manipulationDOM['descriptionSpan'] = document.createElement('div');
  251. this.manipulationDOM['descriptionSpan'].className = 'network-manipulationUI none';
  252. this.manipulationDOM['descriptionLabelSpan'] = document.createElement('div');
  253. this.manipulationDOM['descriptionLabelSpan'].className = 'network-manipulationLabel';
  254. this.manipulationDOM['descriptionLabelSpan'].innerHTML = locale['edgeDescription'];
  255. this.manipulationDOM['descriptionSpan'].appendChild(this.manipulationDOM['descriptionLabelSpan']);
  256. this.manipulationDiv.appendChild(this.manipulationDOM['backSpan']);
  257. this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']);
  258. this.manipulationDiv.appendChild(this.manipulationDOM['descriptionSpan']);
  259. // bind the icon
  260. this._bindHammerToDiv(this.manipulationDOM['backSpan'],'_createManipulatorBar');
  261. // we use the boundFunction so we can reference it when we unbind it from the "select" event.
  262. var me = this;
  263. this.boundFunction = me._handleConnect;
  264. this.on('select', this.boundFunction);
  265. // temporarily overload functions
  266. this.cachedFunctions["_handleTouch"] = this._handleTouch;
  267. this.cachedFunctions["_manipulationReleaseOverload"] = this._manipulationReleaseOverload;
  268. this.cachedFunctions["_handleDragStart"] = this._handleDragStart;
  269. this.cachedFunctions["_handleDragEnd"] = this._handleDragEnd;
  270. this.cachedFunctions["_handleOnHold"] = this._handleOnHold;
  271. this._handleTouch = this._handleConnect;
  272. this._manipulationReleaseOverload = function () {};
  273. this._handleOnHold = function () {};
  274. this._handleDragStart = function () {};
  275. this._handleDragEnd = this._finishConnect;
  276. // redraw to show the unselect
  277. this._redraw();
  278. };
  279. /**
  280. * create the toolbar to edit edges
  281. *
  282. * @private
  283. */
  284. exports._createEditEdgeToolbar = function() {
  285. // clear the toolbar
  286. this._clearManipulatorBar();
  287. this.controlNodesActive = true;
  288. if (this.boundFunction) {
  289. this.off('select', this.boundFunction);
  290. }
  291. this.edgeBeingEdited = this._getSelectedEdge();
  292. this.edgeBeingEdited._enableControlNodes();
  293. var locale = this.constants.locales[this.constants.locale];
  294. this.manipulationDOM = {};
  295. this.manipulationDOM['backSpan'] = document.createElement('div');
  296. this.manipulationDOM['backSpan'].className = 'network-manipulationUI back';
  297. this.manipulationDOM['backLabelSpan'] = document.createElement('div');
  298. this.manipulationDOM['backLabelSpan'].className = 'network-manipulationLabel';
  299. this.manipulationDOM['backLabelSpan'].innerHTML = locale['back'];
  300. this.manipulationDOM['backSpan'].appendChild(this.manipulationDOM['backLabelSpan']);
  301. this.manipulationDOM['seperatorLineDiv1'] = document.createElement('div');
  302. this.manipulationDOM['seperatorLineDiv1'].className = 'network-seperatorLine';
  303. this.manipulationDOM['descriptionSpan'] = document.createElement('div');
  304. this.manipulationDOM['descriptionSpan'].className = 'network-manipulationUI none';
  305. this.manipulationDOM['descriptionLabelSpan'] = document.createElement('div');
  306. this.manipulationDOM['descriptionLabelSpan'].className = 'network-manipulationLabel';
  307. this.manipulationDOM['descriptionLabelSpan'].innerHTML = locale['editEdgeDescription'];
  308. this.manipulationDOM['descriptionSpan'].appendChild(this.manipulationDOM['descriptionLabelSpan']);
  309. this.manipulationDiv.appendChild(this.manipulationDOM['backSpan']);
  310. this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv1']);
  311. this.manipulationDiv.appendChild(this.manipulationDOM['descriptionSpan']);
  312. // bind the icon
  313. this._bindHammerToDiv(this.manipulationDOM['backSpan'],'_createManipulatorBar');
  314. // temporarily overload functions
  315. this.cachedFunctions["_handleTouch"] = this._handleTouch;
  316. this.cachedFunctions["_manipulationReleaseOverload"] = this._manipulationReleaseOverload;
  317. this.cachedFunctions["_handleTap"] = this._handleTap;
  318. this.cachedFunctions["_handleDragStart"] = this._handleDragStart;
  319. this.cachedFunctions["_handleOnDrag"] = this._handleOnDrag;
  320. this._handleTouch = this._selectControlNode;
  321. this._handleTap = function () {};
  322. this._handleOnDrag = this._controlNodeDrag;
  323. this._handleDragStart = function () {}
  324. this._manipulationReleaseOverload = this._releaseControlNode;
  325. // redraw to show the unselect
  326. this._redraw();
  327. };
  328. /**
  329. * the function bound to the selection event. It checks if you want to connect a cluster and changes the description
  330. * to walk the user through the process.
  331. *
  332. * @private
  333. */
  334. exports._selectControlNode = function(pointer) {
  335. this.edgeBeingEdited.controlNodes.from.unselect();
  336. this.edgeBeingEdited.controlNodes.to.unselect();
  337. this.selectedControlNode = this.edgeBeingEdited._getSelectedControlNode(this._XconvertDOMtoCanvas(pointer.x),this._YconvertDOMtoCanvas(pointer.y));
  338. if (this.selectedControlNode !== null) {
  339. this.selectedControlNode.select();
  340. this.freezeSimulation(true);
  341. }
  342. this._redraw();
  343. };
  344. /**
  345. * the function bound to the selection event. It checks if you want to connect a cluster and changes the description
  346. * to walk the user through the process.
  347. *
  348. * @private
  349. */
  350. exports._controlNodeDrag = function(event) {
  351. var pointer = this._getPointer(event.center);
  352. if (this.selectedControlNode !== null && this.selectedControlNode !== undefined) {
  353. this.selectedControlNode.x = this._XconvertDOMtoCanvas(pointer.x);
  354. this.selectedControlNode.y = this._YconvertDOMtoCanvas(pointer.y);
  355. }
  356. this._redraw();
  357. };
  358. /**
  359. *
  360. * @param pointer
  361. * @private
  362. */
  363. exports._releaseControlNode = function(pointer) {
  364. var newNode = this._getNodeAt(pointer);
  365. if (newNode !== null) {
  366. if (this.edgeBeingEdited.controlNodes.from.selected == true) {
  367. this.edgeBeingEdited._restoreControlNodes();
  368. this._editEdge(newNode.id, this.edgeBeingEdited.to.id);
  369. this.edgeBeingEdited.controlNodes.from.unselect();
  370. }
  371. if (this.edgeBeingEdited.controlNodes.to.selected == true) {
  372. this.edgeBeingEdited._restoreControlNodes();
  373. this._editEdge(this.edgeBeingEdited.from.id, newNode.id);
  374. this.edgeBeingEdited.controlNodes.to.unselect();
  375. }
  376. }
  377. else {
  378. this.edgeBeingEdited._restoreControlNodes();
  379. }
  380. this.freezeSimulation(false);
  381. this._redraw();
  382. };
  383. /**
  384. * the function bound to the selection event. It checks if you want to connect a cluster and changes the description
  385. * to walk the user through the process.
  386. *
  387. * @private
  388. */
  389. exports._handleConnect = function(pointer) {
  390. if (this._getSelectedNodeCount() == 0) {
  391. var node = this._getNodeAt(pointer);
  392. if (node != null) {
  393. if (this.isCluster(node.id) == true) {
  394. alert(this.constants.locales[this.constants.locale]['createEdgeError'])
  395. }
  396. else {
  397. this._selectObject(node,false);
  398. var supportNodes = this.body.sectors['support']['nodes'];
  399. // create a node the temporary line can look at
  400. supportNodes['targetNode'] = this.body.functions.createNode({id:'targetNode'});
  401. var targetNode = supportNodes['targetNode'];
  402. targetNode.x = node.x;
  403. targetNode.y = node.y;
  404. // create a temporary edge
  405. this.body.edges['connectionEdge'] = this.body.functions.createEdge({id:"connectionEdge",from:node.id,to:targetNode.id});
  406. var connectionEdge = this.body.edges['connectionEdge'];
  407. connectionEdge.from = node;
  408. connectionEdge.connected = true;
  409. connectionEdge.options.smoothCurves = {enabled: true,
  410. dynamic: false,
  411. type: "continuous",
  412. roundness: 0.5
  413. };
  414. connectionEdge.selected = true;
  415. connectionEdge.to = targetNode;
  416. this.cachedFunctions["_handleOnDrag"] = this._handleOnDrag;
  417. var me = this;
  418. this._handleOnDrag = function(event) {
  419. var pointer = me._getPointer(event.center);
  420. var connectionEdge = me.body.edges['connectionEdge'];
  421. connectionEdge.to.x = me._XconvertDOMtoCanvas(pointer.x);
  422. connectionEdge.to.y = me._YconvertDOMtoCanvas(pointer.y);
  423. me._redraw();
  424. };
  425. }
  426. }
  427. }
  428. };
  429. exports._finishConnect = function(event) {
  430. if (this._getSelectedNodeCount() == 1) {
  431. var pointer = this._getPointer(event.center);
  432. // restore the drag function
  433. this._handleOnDrag = this.cachedFunctions["_handleOnDrag"];
  434. delete this.cachedFunctions["_handleOnDrag"];
  435. // remember the edge id
  436. var connectFromId = this.body.edges['connectionEdge'].fromId;
  437. // remove the temporary nodes and edge
  438. delete this.body.edges['connectionEdge'];
  439. delete this.body.sectors['support']['nodes']['targetNode'];
  440. delete this.body.sectors['support']['nodes']['targetViaNode'];
  441. var node = this._getNodeAt(pointer);
  442. if (node != null) {
  443. if (this.isCluster(node.id) === true) {
  444. alert(this.constants.locales[this.constants.locale]["createEdgeError"])
  445. }
  446. else {
  447. this._createEdge(connectFromId,node.id);
  448. this._createManipulatorBar();
  449. }
  450. }
  451. this._unselectAll();
  452. }
  453. };
  454. /**
  455. * Adds a node on the specified location
  456. */
  457. exports._addNode = function() {
  458. if (this._selectionIsEmpty() && this.editMode == true) {
  459. var positionObject = this._pointerToPositionObject(this.pointerPosition);
  460. var defaultData = {id:util.randomUUID(),x:positionObject.left,y:positionObject.top,label:"new",allowedToMoveX:true,allowedToMoveY:true};
  461. if (this.triggerFunctions.add) {
  462. if (this.triggerFunctions.add.length == 2) {
  463. var me = this;
  464. this.triggerFunctions.add(defaultData, function(finalizedData) {
  465. me.body.data.nodes.add(finalizedData);
  466. me._createManipulatorBar();
  467. me.moving = true;
  468. me.start();
  469. });
  470. }
  471. else {
  472. throw new Error('The function for add does not support two arguments (data,callback)');
  473. this._createManipulatorBar();
  474. this.moving = true;
  475. this.start();
  476. }
  477. }
  478. else {
  479. this.body.data.nodes.add(defaultData);
  480. this._createManipulatorBar();
  481. this.moving = true;
  482. this.start();
  483. }
  484. }
  485. };
  486. /**
  487. * connect two nodes with a new edge.
  488. *
  489. * @private
  490. */
  491. exports._createEdge = function(sourceNodeId,targetNodeId) {
  492. if (this.editMode == true) {
  493. var defaultData = {from:sourceNodeId, to:targetNodeId};
  494. if (this.triggerFunctions.connect) {
  495. if (this.triggerFunctions.connect.length == 2) {
  496. var me = this;
  497. this.triggerFunctions.connect(defaultData, function(finalizedData) {
  498. me.body.data.edges.add(finalizedData);
  499. me.moving = true;
  500. me.start();
  501. });
  502. }
  503. else {
  504. throw new Error('The function for connect does not support two arguments (data,callback)');
  505. this.moving = true;
  506. this.start();
  507. }
  508. }
  509. else {
  510. this.body.data.edges.add(defaultData);
  511. this.moving = true;
  512. this.start();
  513. }
  514. }
  515. };
  516. /**
  517. * connect two nodes with a new edge.
  518. *
  519. * @private
  520. */
  521. exports._editEdge = function(sourceNodeId,targetNodeId) {
  522. if (this.editMode == true) {
  523. var defaultData = {id: this.edgeBeingEdited.id, from:sourceNodeId, to:targetNodeId};
  524. console.log(defaultData);
  525. if (this.triggerFunctions.editEdge) {
  526. if (this.triggerFunctions.editEdge.length == 2) {
  527. var me = this;
  528. this.triggerFunctions.editEdge(defaultData, function(finalizedData) {
  529. me.body.data.edges.update(finalizedData);
  530. me.moving = true;
  531. me.start();
  532. });
  533. }
  534. else {
  535. throw new Error('The function for edit does not support two arguments (data, callback)');
  536. this.moving = true;
  537. this.start();
  538. }
  539. }
  540. else {
  541. this.body.data.edges.update(defaultData);
  542. this.moving = true;
  543. this.start();
  544. }
  545. }
  546. };
  547. /**
  548. * Create the toolbar to edit the selected node. The label and the color can be changed. Other colors are derived from the chosen color.
  549. *
  550. * @private
  551. */
  552. exports._editNode = function() {
  553. if (this.triggerFunctions.edit && this.editMode == true) {
  554. var node = this._getSelectedNode();
  555. var data = {id:node.id,
  556. label: node.label,
  557. group: node.options.group,
  558. shape: node.options.shape,
  559. color: {
  560. background:node.options.color.background,
  561. border:node.options.color.border,
  562. highlight: {
  563. background:node.options.color.highlight.background,
  564. border:node.options.color.highlight.border
  565. }
  566. }};
  567. if (this.triggerFunctions.edit.length == 2) {
  568. var me = this;
  569. this.triggerFunctions.edit(data, function (finalizedData) {
  570. me.body.data.nodes.update(finalizedData);
  571. me._createManipulatorBar();
  572. me.moving = true;
  573. me.start();
  574. });
  575. }
  576. else {
  577. throw new Error('The function for edit does not support two arguments (data, callback)');
  578. }
  579. }
  580. else {
  581. throw new Error('No edit function has been bound to this button');
  582. }
  583. };
  584. /**
  585. * delete everything in the selection
  586. *
  587. * @private
  588. */
  589. exports._deleteSelected = function() {
  590. if (!this._selectionIsEmpty() && this.editMode == true) {
  591. if (!this._clusterInSelection()) {
  592. var selectedNodes = this.getSelectedNodes();
  593. var selectedEdges = this.getSelectedEdges();
  594. if (this.triggerFunctions.del) {
  595. var me = this;
  596. var data = {nodes: selectedNodes, edges: selectedEdges};
  597. if (this.triggerFunctions.del.length == 2) {
  598. this.triggerFunctions.del(data, function (finalizedData) {
  599. me.body.data.edges.remove(finalizedData.edges);
  600. me.body.data.nodes.remove(finalizedData.nodes);
  601. me._unselectAll();
  602. me.moving = true;
  603. me.start();
  604. });
  605. }
  606. else {
  607. throw new Error('The function for delete does not support two arguments (data, callback)')
  608. }
  609. }
  610. else {
  611. this.body.data.edges.remove(selectedEdges);
  612. this.body.data.nodes.remove(selectedNodes);
  613. this._unselectAll();
  614. this.moving = true;
  615. this.start();
  616. }
  617. }
  618. else {
  619. alert(this.constants.locales[this.constants.locale]["deleteClusterError"]);
  620. }
  621. }
  622. };