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. /**
  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.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.freezeSimulationEnabled = 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._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.freezeSimulationEnabled = 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.freezeSimulationEnabled = 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. this._handleOnDrag = function(event) {
  418. var pointer = this._getPointer(event.gesture.center);
  419. var connectionEdge = this.edges['connectionEdge'];
  420. connectionEdge.to.x = this._XconvertDOMtoCanvas(pointer.x);
  421. connectionEdge.to.y = this._YconvertDOMtoCanvas(pointer.y);
  422. };
  423. this.moving = true;
  424. this.start();
  425. }
  426. }
  427. }
  428. };
  429. exports._finishConnect = function(event) {
  430. if (this._getSelectedNodeCount() == 1) {
  431. var pointer = this._getPointer(event.gesture.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.edges['connectionEdge'].fromId;
  437. // remove the temporary nodes and edge
  438. delete this.edges['connectionEdge'];
  439. delete this.sectors['support']['nodes']['targetNode'];
  440. delete this.sectors['support']['nodes']['targetViaNode'];
  441. var node = this._getNodeAt(pointer);
  442. if (node != null) {
  443. if (node.clusterSize > 1) {
  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.nodesData.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.nodesData.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.edgesData.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.edgesData.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. if (this.triggerFunctions.editEdge) {
  525. if (this.triggerFunctions.editEdge.length == 2) {
  526. var me = this;
  527. this.triggerFunctions.editEdge(defaultData, function(finalizedData) {
  528. me.edgesData.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.edgesData.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.nodesData.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.edgesData.remove(finalizedData.edges);
  599. me.nodesData.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.edgesData.remove(selectedEdges);
  611. this.nodesData.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. };