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.

717 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.sectors['support']['nodes']['targetNode'];
  16. delete this.sectors['support']['nodes']['targetViaNode'];
  17. this.controlNodesActive = false;
  18. this.freezeSimulation(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.freezeSimulation(true);
  234. if (this.boundFunction) {
  235. this.off('select', this.boundFunction);
  236. }
  237. var locale = this.constants.locales[this.constants.locale];
  238. this._unselectAll();
  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.gesture.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 (node.clusterSize > 1) {
  394. alert(this.constants.locales[this.constants.locale]['createEdgeError'])
  395. }
  396. else {
  397. this._selectObject(node,false);
  398. var supportNodes = this.sectors['support']['nodes'];
  399. // create a node the temporary line can look at
  400. supportNodes['targetNode'] = new Node({id:'targetNode'},{},{},this.constants);
  401. var targetNode = supportNodes['targetNode'];
  402. targetNode.x = node.x;
  403. targetNode.y = node.y;
  404. // create a temporary edge
  405. this.edges['connectionEdge'] = new Edge({id:"connectionEdge",from:node.id,to:targetNode.id}, this, this.constants);
  406. var connectionEdge = this.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 = this._getPointer(event.gesture.center);
  420. var connectionEdge = me.edges['connectionEdge'];
  421. connectionEdge.to.x = me._XconvertDOMtoCanvas(pointer.x);
  422. connectionEdge.to.y = me._YconvertDOMtoCanvas(pointer.y);
  423. me._redraw();
  424. };
  425. this.moving = true;
  426. this.start();
  427. }
  428. }
  429. }
  430. };
  431. exports._finishConnect = function(event) {
  432. if (this._getSelectedNodeCount() == 1) {
  433. var pointer = this._getPointer(event.gesture.center);
  434. // restore the drag function
  435. this._handleOnDrag = this.cachedFunctions["_handleOnDrag"];
  436. delete this.cachedFunctions["_handleOnDrag"];
  437. // remember the edge id
  438. var connectFromId = this.edges['connectionEdge'].fromId;
  439. // remove the temporary nodes and edge
  440. delete this.edges['connectionEdge'];
  441. delete this.sectors['support']['nodes']['targetNode'];
  442. delete this.sectors['support']['nodes']['targetViaNode'];
  443. var node = this._getNodeAt(pointer);
  444. if (node != null) {
  445. if (node.clusterSize > 1) {
  446. alert(this.constants.locales[this.constants.locale]["createEdgeError"])
  447. }
  448. else {
  449. this._createEdge(connectFromId,node.id);
  450. this._createManipulatorBar();
  451. }
  452. }
  453. this._unselectAll();
  454. }
  455. };
  456. /**
  457. * Adds a node on the specified location
  458. */
  459. exports._addNode = function() {
  460. if (this._selectionIsEmpty() && this.editMode == true) {
  461. var positionObject = this._pointerToPositionObject(this.pointerPosition);
  462. var defaultData = {id:util.randomUUID(),x:positionObject.left,y:positionObject.top,label:"new",allowedToMoveX:true,allowedToMoveY:true};
  463. if (this.triggerFunctions.add) {
  464. if (this.triggerFunctions.add.length == 2) {
  465. var me = this;
  466. this.triggerFunctions.add(defaultData, function(finalizedData) {
  467. me.nodesData.add(finalizedData);
  468. me._createManipulatorBar();
  469. me.moving = true;
  470. me.start();
  471. });
  472. }
  473. else {
  474. throw new Error('The function for add does not support two arguments (data,callback)');
  475. this._createManipulatorBar();
  476. this.moving = true;
  477. this.start();
  478. }
  479. }
  480. else {
  481. this.nodesData.add(defaultData);
  482. this._createManipulatorBar();
  483. this.moving = true;
  484. this.start();
  485. }
  486. }
  487. };
  488. /**
  489. * connect two nodes with a new edge.
  490. *
  491. * @private
  492. */
  493. exports._createEdge = function(sourceNodeId,targetNodeId) {
  494. if (this.editMode == true) {
  495. var defaultData = {from:sourceNodeId, to:targetNodeId};
  496. if (this.triggerFunctions.connect) {
  497. if (this.triggerFunctions.connect.length == 2) {
  498. var me = this;
  499. this.triggerFunctions.connect(defaultData, function(finalizedData) {
  500. me.edgesData.add(finalizedData);
  501. me.moving = true;
  502. me.start();
  503. });
  504. }
  505. else {
  506. throw new Error('The function for connect does not support two arguments (data,callback)');
  507. this.moving = true;
  508. this.start();
  509. }
  510. }
  511. else {
  512. this.edgesData.add(defaultData);
  513. this.moving = true;
  514. this.start();
  515. }
  516. }
  517. };
  518. /**
  519. * connect two nodes with a new edge.
  520. *
  521. * @private
  522. */
  523. exports._editEdge = function(sourceNodeId,targetNodeId) {
  524. if (this.editMode == true) {
  525. var defaultData = {id: this.edgeBeingEdited.id, from:sourceNodeId, to:targetNodeId};
  526. if (this.triggerFunctions.editEdge) {
  527. if (this.triggerFunctions.editEdge.length == 2) {
  528. var me = this;
  529. this.triggerFunctions.editEdge(defaultData, function(finalizedData) {
  530. me.edgesData.update(finalizedData);
  531. me.moving = true;
  532. me.start();
  533. });
  534. }
  535. else {
  536. throw new Error('The function for edit does not support two arguments (data, callback)');
  537. this.moving = true;
  538. this.start();
  539. }
  540. }
  541. else {
  542. this.edgesData.update(defaultData);
  543. this.moving = true;
  544. this.start();
  545. }
  546. }
  547. };
  548. /**
  549. * Create the toolbar to edit the selected node. The label and the color can be changed. Other colors are derived from the chosen color.
  550. *
  551. * @private
  552. */
  553. exports._editNode = function() {
  554. if (this.triggerFunctions.edit && this.editMode == true) {
  555. var node = this._getSelectedNode();
  556. var data = {id:node.id,
  557. label: node.label,
  558. group: node.options.group,
  559. shape: node.options.shape,
  560. color: {
  561. background:node.options.color.background,
  562. border:node.options.color.border,
  563. highlight: {
  564. background:node.options.color.highlight.background,
  565. border:node.options.color.highlight.border
  566. }
  567. }};
  568. if (this.triggerFunctions.edit.length == 2) {
  569. var me = this;
  570. this.triggerFunctions.edit(data, function (finalizedData) {
  571. me.nodesData.update(finalizedData);
  572. me._createManipulatorBar();
  573. me.moving = true;
  574. me.start();
  575. });
  576. }
  577. else {
  578. throw new Error('The function for edit does not support two arguments (data, callback)');
  579. }
  580. }
  581. else {
  582. throw new Error('No edit function has been bound to this button');
  583. }
  584. };
  585. /**
  586. * delete everything in the selection
  587. *
  588. * @private
  589. */
  590. exports._deleteSelected = function() {
  591. if (!this._selectionIsEmpty() && this.editMode == true) {
  592. if (!this._clusterInSelection()) {
  593. var selectedNodes = this.getSelectedNodes();
  594. var selectedEdges = this.getSelectedEdges();
  595. if (this.triggerFunctions.del) {
  596. var me = this;
  597. var data = {nodes: selectedNodes, edges: selectedEdges};
  598. if (this.triggerFunctions.del.length == 2) {
  599. this.triggerFunctions.del(data, function (finalizedData) {
  600. me.edgesData.remove(finalizedData.edges);
  601. me.nodesData.remove(finalizedData.nodes);
  602. me._unselectAll();
  603. me.moving = true;
  604. me.start();
  605. });
  606. }
  607. else {
  608. throw new Error('The function for delete does not support two arguments (data, callback)')
  609. }
  610. }
  611. else {
  612. this.edgesData.remove(selectedEdges);
  613. this.nodesData.remove(selectedNodes);
  614. this._unselectAll();
  615. this.moving = true;
  616. this.start();
  617. }
  618. }
  619. else {
  620. alert(this.constants.locales[this.constants.locale]["deleteClusterError"]);
  621. }
  622. }
  623. };