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.

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