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.

690 lines
25 KiB

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