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.

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